2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA sensor."""
|
2024-03-08 13:44:56 +00:00
|
|
|
|
2023-12-27 15:25:41 +00:00
|
|
|
from datetime import timedelta
|
2021-10-03 01:57:49 +00:00
|
|
|
import math
|
2023-05-01 16:32:40 +00:00
|
|
|
from unittest.mock import MagicMock, patch
|
2020-01-18 01:53:31 +00:00
|
|
|
|
2020-01-11 01:30:58 +00:00
|
|
|
import pytest
|
2020-09-29 19:25:05 +00:00
|
|
|
import zigpy.profiles.zha
|
2024-02-29 15:38:21 +00:00
|
|
|
from zigpy.quirks import CustomCluster
|
|
|
|
from zigpy.quirks.v2 import CustomDeviceV2, add_to_registry_v2
|
|
|
|
from zigpy.quirks.v2.homeassistant import UnitOfMass
|
|
|
|
import zigpy.types as t
|
2024-01-31 02:26:19 +00:00
|
|
|
from zigpy.zcl.clusters import general, homeautomation, hvac, measurement, smartenergy
|
|
|
|
from zigpy.zcl.clusters.hvac import Thermostat
|
2024-02-29 15:38:21 +00:00
|
|
|
from zigpy.zcl.clusters.manufacturer_specific import ManufacturerSpecificCluster
|
2019-10-21 17:14:17 +00:00
|
|
|
|
2021-12-11 16:51:24 +00:00
|
|
|
from homeassistant.components.sensor import SensorDeviceClass
|
2024-02-23 18:22:47 +00:00
|
|
|
from homeassistant.components.zha.core import ZHADevice
|
2023-04-19 14:47:07 +00:00
|
|
|
from homeassistant.components.zha.core.const import ZHA_CLUSTER_HANDLER_READS_PER_REQ
|
2020-01-11 01:30:58 +00:00
|
|
|
import homeassistant.config as config_util
|
|
|
|
from homeassistant.const import (
|
2021-09-29 16:35:20 +00:00
|
|
|
ATTR_DEVICE_CLASS,
|
2020-01-11 01:30:58 +00:00
|
|
|
ATTR_UNIT_OF_MEASUREMENT,
|
|
|
|
CONF_UNIT_SYSTEM,
|
|
|
|
CONF_UNIT_SYSTEM_IMPERIAL,
|
|
|
|
CONF_UNIT_SYSTEM_METRIC,
|
2020-09-23 18:48:01 +00:00
|
|
|
LIGHT_LUX,
|
2020-09-05 19:09:14 +00:00
|
|
|
PERCENTAGE,
|
2020-01-11 01:30:58 +00:00
|
|
|
STATE_UNAVAILABLE,
|
|
|
|
STATE_UNKNOWN,
|
2021-12-11 16:06:39 +00:00
|
|
|
Platform,
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfApparentPower,
|
|
|
|
UnitOfElectricCurrent,
|
|
|
|
UnitOfElectricPotential,
|
|
|
|
UnitOfEnergy,
|
|
|
|
UnitOfPower,
|
|
|
|
UnitOfPressure,
|
|
|
|
UnitOfTemperature,
|
|
|
|
UnitOfVolume,
|
2020-01-11 01:30:58 +00:00
|
|
|
)
|
2023-02-17 17:54:26 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
2024-02-23 18:22:47 +00:00
|
|
|
from homeassistant.helpers import entity_registry as er, restore_state
|
2021-10-03 01:57:49 +00:00
|
|
|
from homeassistant.helpers.entity_component import async_update_entity
|
2020-01-11 01:30:58 +00:00
|
|
|
from homeassistant.util import dt as dt_util
|
2019-10-21 17:14:17 +00:00
|
|
|
|
2019-02-03 21:03:35 +00:00
|
|
|
from .common import (
|
2019-10-21 17:14:17 +00:00
|
|
|
async_enable_traffic,
|
2020-02-12 21:12:14 +00:00
|
|
|
async_test_rejoin,
|
2019-10-31 16:31:06 +00:00
|
|
|
find_entity_id,
|
2021-09-29 16:35:20 +00:00
|
|
|
find_entity_ids,
|
2020-03-13 23:17:50 +00:00
|
|
|
send_attribute_report,
|
|
|
|
send_attributes_report,
|
2019-02-03 21:03:35 +00:00
|
|
|
)
|
2021-10-03 01:57:49 +00:00
|
|
|
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
|
2019-02-03 21:03:35 +00:00
|
|
|
|
2023-12-27 15:25:41 +00:00
|
|
|
from tests.common import (
|
2024-02-23 18:22:47 +00:00
|
|
|
MockConfigEntry,
|
2023-12-27 15:25:41 +00:00
|
|
|
async_fire_time_changed,
|
|
|
|
async_mock_load_restore_state_from_storage,
|
|
|
|
)
|
2023-05-31 01:48:17 +00:00
|
|
|
|
2022-07-10 20:17:59 +00:00
|
|
|
ENTITY_ID_PREFIX = "sensor.fakemanufacturer_fakemodel_{}"
|
2021-09-29 16:35:20 +00:00
|
|
|
|
2019-02-03 21:03:35 +00:00
|
|
|
|
2022-06-17 16:41:10 +00:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def sensor_platform_only():
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Only set up the sensor and required base platforms to speed up tests."""
|
2022-06-17 16:41:10 +00:00
|
|
|
with patch(
|
|
|
|
"homeassistant.components.zha.PLATFORMS",
|
|
|
|
(
|
|
|
|
Platform.DEVICE_TRACKER,
|
|
|
|
Platform.SENSOR,
|
|
|
|
),
|
|
|
|
):
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
2021-10-03 01:57:49 +00:00
|
|
|
@pytest.fixture
|
2024-01-24 12:56:49 +00:00
|
|
|
async def elec_measurement_zigpy_dev(hass: HomeAssistant, zigpy_device_mock):
|
2021-10-03 01:57:49 +00:00
|
|
|
"""Electric Measurement zigpy device."""
|
|
|
|
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
|
|
|
SIG_EP_INPUT: [
|
|
|
|
general.Basic.cluster_id,
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
|
|
|
],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.SIMPLE_SENSOR,
|
|
|
|
SIG_EP_PROFILE: zigpy.profiles.zha.PROFILE_ID,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
zigpy_device.node_desc.mac_capability_flags |= 0b_0000_0100
|
|
|
|
zigpy_device.endpoints[1].electrical_measurement.PLUGGED_ATTR_READS = {
|
|
|
|
"ac_current_divisor": 10,
|
|
|
|
"ac_current_multiplier": 1,
|
|
|
|
"ac_power_divisor": 10,
|
|
|
|
"ac_power_multiplier": 1,
|
|
|
|
"ac_voltage_divisor": 10,
|
|
|
|
"ac_voltage_multiplier": 1,
|
|
|
|
"measurement_type": 8,
|
|
|
|
"power_divisor": 10,
|
|
|
|
"power_multiplier": 1,
|
|
|
|
}
|
|
|
|
return zigpy_device
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
async def elec_measurement_zha_dev(elec_measurement_zigpy_dev, zha_device_joined):
|
|
|
|
"""Electric Measurement ZHA device."""
|
|
|
|
|
|
|
|
zha_dev = await zha_device_joined(elec_measurement_zigpy_dev)
|
|
|
|
zha_dev.available = True
|
|
|
|
return zha_dev
|
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_humidity(hass: HomeAssistant, cluster, entity_id):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Test humidity sensor."""
|
2020-03-13 23:17:50 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1: 1, 0: 1000, 2: 100})
|
2020-09-05 19:09:14 +00:00
|
|
|
assert_state(hass, entity_id, "10.0", PERCENTAGE)
|
2019-02-03 21:03:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_temperature(hass: HomeAssistant, cluster, entity_id):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Test temperature sensor."""
|
2020-03-13 23:17:50 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1: 1, 0: 2900, 2: 100})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "29.0", UnitOfTemperature.CELSIUS)
|
2019-02-03 21:03:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_pressure(hass: HomeAssistant, cluster, entity_id):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Test pressure sensor."""
|
2020-03-13 23:17:50 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1: 1, 0: 1000, 2: 10000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "1000", UnitOfPressure.HPA)
|
2020-03-13 23:17:50 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1000, 20: -1, 16: 10000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "1000", UnitOfPressure.HPA)
|
2019-02-03 21:03:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_illuminance(hass: HomeAssistant, cluster, entity_id):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Test illuminance sensor."""
|
2020-03-13 23:17:50 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1: 1, 0: 10, 2: 20})
|
2022-12-23 12:24:15 +00:00
|
|
|
assert_state(hass, entity_id, "1", LIGHT_LUX)
|
2019-02-03 21:03:35 +00:00
|
|
|
|
2024-01-21 01:37:13 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1: 0, 0: 0, 2: 20})
|
|
|
|
assert_state(hass, entity_id, "0", LIGHT_LUX)
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {1: 0, 0: 0xFFFF, 2: 20})
|
|
|
|
assert_state(hass, entity_id, "unknown", LIGHT_LUX)
|
|
|
|
|
2019-02-03 21:03:35 +00:00
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_metering(hass: HomeAssistant, cluster, entity_id):
|
2021-09-29 16:35:20 +00:00
|
|
|
"""Test Smart Energy metering sensor."""
|
2020-03-13 23:17:50 +00:00
|
|
|
await send_attributes_report(hass, cluster, {1025: 1, 1024: 12345, 1026: 100})
|
2021-09-29 16:35:20 +00:00
|
|
|
assert_state(hass, entity_id, "12345.0", None)
|
|
|
|
assert hass.states.get(entity_id).attributes["status"] == "NO_ALARMS"
|
|
|
|
assert hass.states.get(entity_id).attributes["device_type"] == "Electric Metering"
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {1024: 12346, "status": 64 + 8})
|
|
|
|
assert_state(hass, entity_id, "12346.0", None)
|
2023-02-15 17:40:48 +00:00
|
|
|
assert hass.states.get(entity_id).attributes["status"] in (
|
|
|
|
"SERVICE_DISCONNECT|POWER_FAILURE",
|
|
|
|
"POWER_FAILURE|SERVICE_DISCONNECT",
|
2021-09-29 16:35:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
await send_attributes_report(
|
2024-01-30 20:09:15 +00:00
|
|
|
hass, cluster, {"status": 64 + 8, "metering_device_type": 1}
|
|
|
|
)
|
|
|
|
assert hass.states.get(entity_id).attributes["status"] in (
|
|
|
|
"SERVICE_DISCONNECT|NOT_DEFINED",
|
|
|
|
"NOT_DEFINED|SERVICE_DISCONNECT",
|
|
|
|
)
|
|
|
|
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {"status": 64 + 8, "metering_device_type": 2}
|
|
|
|
)
|
|
|
|
assert hass.states.get(entity_id).attributes["status"] in (
|
|
|
|
"SERVICE_DISCONNECT|PIPE_EMPTY",
|
|
|
|
"PIPE_EMPTY|SERVICE_DISCONNECT",
|
|
|
|
)
|
|
|
|
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {"status": 64 + 8, "metering_device_type": 5}
|
|
|
|
)
|
|
|
|
assert hass.states.get(entity_id).attributes["status"] in (
|
|
|
|
"SERVICE_DISCONNECT|TEMPERATURE_SENSOR",
|
|
|
|
"TEMPERATURE_SENSOR|SERVICE_DISCONNECT",
|
|
|
|
)
|
|
|
|
|
|
|
|
# Status for other meter types
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {"status": 32, "metering_device_type": 4}
|
2021-09-29 16:35:20 +00:00
|
|
|
)
|
2023-02-15 17:40:48 +00:00
|
|
|
assert hass.states.get(entity_id).attributes["status"] in ("<bitmap8.32: 32>", "32")
|
2021-09-29 16:35:20 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_smart_energy_summation_delivered(
|
|
|
|
hass: HomeAssistant, cluster, entity_id
|
|
|
|
):
|
|
|
|
"""Test SmartEnergy Summation delivered sensor."""
|
2021-09-29 16:35:20 +00:00
|
|
|
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {1025: 1, "current_summ_delivered": 12321, 1026: 100}
|
|
|
|
)
|
2024-01-16 23:40:00 +00:00
|
|
|
assert_state(hass, entity_id, "12.321", UnitOfEnergy.KILO_WATT_HOUR)
|
2021-09-29 16:35:20 +00:00
|
|
|
assert hass.states.get(entity_id).attributes["status"] == "NO_ALARMS"
|
|
|
|
assert hass.states.get(entity_id).attributes["device_type"] == "Electric Metering"
|
|
|
|
assert (
|
2021-12-11 16:51:24 +00:00
|
|
|
hass.states.get(entity_id).attributes[ATTR_DEVICE_CLASS]
|
|
|
|
== SensorDeviceClass.ENERGY
|
2021-09-29 16:35:20 +00:00
|
|
|
)
|
2019-02-03 21:03:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
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):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Test electrical measurement sensor."""
|
2021-10-03 01:57:49 +00:00
|
|
|
# update divisor cached value
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 1})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 100, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "100", UnitOfPower.WATT)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 99, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "99", UnitOfPower.WATT)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 10})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 1000, 10: 5000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "100", UnitOfPower.WATT)
|
2020-01-18 01:53:31 +00:00
|
|
|
|
2021-10-03 01:57:49 +00:00
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 99, 10: 5000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "9.9", UnitOfPower.WATT)
|
2020-01-18 01:53:31 +00:00
|
|
|
|
2021-10-03 01:57:49 +00:00
|
|
|
assert "active_power_max" not in hass.states.get(entity_id).attributes
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050D: 88, 10: 5000})
|
|
|
|
assert hass.states.get(entity_id).attributes["active_power_max"] == "8.8"
|
2020-02-10 02:45:35 +00:00
|
|
|
|
2021-10-03 01:57:49 +00:00
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_em_apparent_power(hass: HomeAssistant, cluster, entity_id):
|
2021-11-19 00:43:08 +00:00
|
|
|
"""Test electrical measurement Apparent Power sensor."""
|
|
|
|
# update divisor cached value
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 1})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050F: 100, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "100", UnitOfApparentPower.VOLT_AMPERE)
|
2021-11-19 00:43:08 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050F: 99, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "99", UnitOfApparentPower.VOLT_AMPERE)
|
2021-11-19 00:43:08 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 10})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050F: 1000, 10: 5000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "100", UnitOfApparentPower.VOLT_AMPERE)
|
2021-11-19 00:43:08 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050F: 99, 10: 5000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "9.9", UnitOfApparentPower.VOLT_AMPERE)
|
2021-11-19 00:43:08 +00:00
|
|
|
|
|
|
|
|
2024-01-30 22:11:18 +00:00
|
|
|
async def async_test_em_power_factor(hass: HomeAssistant, cluster, entity_id):
|
|
|
|
"""Test electrical measurement Power Factor sensor."""
|
|
|
|
# update divisor cached value
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 1})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0510: 100, 10: 1000})
|
|
|
|
assert_state(hass, entity_id, "100", PERCENTAGE)
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0510: 99, 10: 1000})
|
|
|
|
assert_state(hass, entity_id, "99", PERCENTAGE)
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_power_divisor": 10})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0510: 100, 10: 5000})
|
|
|
|
assert_state(hass, entity_id, "100", PERCENTAGE)
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0510: 99, 10: 5000})
|
|
|
|
assert_state(hass, entity_id, "99", PERCENTAGE)
|
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_em_rms_current(hass: HomeAssistant, cluster, entity_id):
|
2021-10-03 01:57:49 +00:00
|
|
|
"""Test electrical measurement RMS Current sensor."""
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0508: 1234, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "1.2", UnitOfElectricCurrent.AMPERE)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_current_divisor": 10})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0508: 236, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "23.6", UnitOfElectricCurrent.AMPERE)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0508: 1236, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "124", UnitOfElectricCurrent.AMPERE)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
assert "rms_current_max" not in hass.states.get(entity_id).attributes
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x050A: 88, 10: 5000})
|
|
|
|
assert hass.states.get(entity_id).attributes["rms_current_max"] == "8.8"
|
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_em_rms_voltage(hass: HomeAssistant, cluster, entity_id):
|
2021-10-03 01:57:49 +00:00
|
|
|
"""Test electrical measurement RMS Voltage sensor."""
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0505: 1234, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "123", UnitOfElectricPotential.VOLT)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0505: 234, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "23.4", UnitOfElectricPotential.VOLT)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {"ac_voltage_divisor": 100})
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0505: 2236, 10: 1000})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "22.4", UnitOfElectricPotential.VOLT)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
assert "rms_voltage_max" not in hass.states.get(entity_id).attributes
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 0x0507: 888, 10: 5000})
|
|
|
|
assert hass.states.get(entity_id).attributes["rms_voltage_max"] == "8.9"
|
2020-02-10 02:45:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_powerconfiguration(hass: HomeAssistant, cluster, entity_id):
|
2020-11-19 02:34:12 +00:00
|
|
|
"""Test powerconfiguration/battery sensor."""
|
|
|
|
await send_attributes_report(hass, cluster, {33: 98})
|
|
|
|
assert_state(hass, entity_id, "49", "%")
|
|
|
|
assert hass.states.get(entity_id).attributes["battery_voltage"] == 2.9
|
|
|
|
assert hass.states.get(entity_id).attributes["battery_quantity"] == 3
|
|
|
|
assert hass.states.get(entity_id).attributes["battery_size"] == "AAA"
|
|
|
|
await send_attributes_report(hass, cluster, {32: 20})
|
|
|
|
assert hass.states.get(entity_id).attributes["battery_voltage"] == 2.0
|
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_powerconfiguration2(hass: HomeAssistant, cluster, entity_id):
|
2022-08-12 01:13:27 +00:00
|
|
|
"""Test powerconfiguration/battery sensor."""
|
|
|
|
await send_attributes_report(hass, cluster, {33: -1})
|
|
|
|
assert_state(hass, entity_id, STATE_UNKNOWN, "%")
|
2023-12-11 18:17:06 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {33: 255})
|
|
|
|
assert_state(hass, entity_id, STATE_UNKNOWN, "%")
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {33: 98})
|
|
|
|
assert_state(hass, entity_id, "49", "%")
|
2022-08-12 01:13:27 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
async def async_test_device_temperature(hass: HomeAssistant, cluster, entity_id):
|
2022-01-23 14:37:01 +00:00
|
|
|
"""Test temperature sensor."""
|
|
|
|
await send_attributes_report(hass, cluster, {0: 2900})
|
2023-01-15 18:14:02 +00:00
|
|
|
assert_state(hass, entity_id, "29.0", UnitOfTemperature.CELSIUS)
|
2022-01-23 14:37:01 +00:00
|
|
|
|
|
|
|
|
2024-01-31 02:26:19 +00:00
|
|
|
async def async_test_setpoint_change_source(hass, cluster, entity_id):
|
|
|
|
"""Test the translation of numerical state into enum text."""
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {Thermostat.AttributeDefs.setpoint_change_source.id: 0x01}
|
|
|
|
)
|
|
|
|
hass_state = hass.states.get(entity_id)
|
|
|
|
assert hass_state.state == "Schedule"
|
|
|
|
|
|
|
|
|
|
|
|
async def async_test_pi_heating_demand(hass, cluster, entity_id):
|
|
|
|
"""Test pi heating demand is correctly returned."""
|
|
|
|
await send_attributes_report(
|
|
|
|
hass, cluster, {Thermostat.AttributeDefs.pi_heating_demand.id: 1}
|
|
|
|
)
|
|
|
|
assert_state(hass, entity_id, "1", "%")
|
|
|
|
|
|
|
|
|
2020-02-10 02:45:35 +00:00
|
|
|
@pytest.mark.parametrize(
|
2023-02-15 13:09:50 +00:00
|
|
|
(
|
|
|
|
"cluster_id",
|
|
|
|
"entity_suffix",
|
|
|
|
"test_func",
|
|
|
|
"report_count",
|
|
|
|
"read_plug",
|
|
|
|
"unsupported_attrs",
|
2024-02-06 00:12:56 +00:00
|
|
|
"initial_sensor_state",
|
2023-02-15 13:09:50 +00:00
|
|
|
),
|
2024-03-19 08:01:07 +00:00
|
|
|
[
|
2021-09-29 16:35:20 +00:00
|
|
|
(
|
|
|
|
measurement.RelativeHumidity.cluster_id,
|
|
|
|
"humidity",
|
|
|
|
async_test_humidity,
|
|
|
|
1,
|
|
|
|
None,
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
2020-11-19 02:34:12 +00:00
|
|
|
(
|
|
|
|
measurement.TemperatureMeasurement.cluster_id,
|
2021-09-29 16:35:20 +00:00
|
|
|
"temperature",
|
2020-11-19 02:34:12 +00:00
|
|
|
async_test_temperature,
|
|
|
|
1,
|
|
|
|
None,
|
2021-09-29 16:35:20 +00:00
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
measurement.PressureMeasurement.cluster_id,
|
|
|
|
"pressure",
|
|
|
|
async_test_pressure,
|
|
|
|
1,
|
|
|
|
None,
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2020-11-19 02:34:12 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
measurement.IlluminanceMeasurement.cluster_id,
|
2021-09-29 16:35:20 +00:00
|
|
|
"illuminance",
|
2020-11-19 02:34:12 +00:00
|
|
|
async_test_illuminance,
|
|
|
|
1,
|
|
|
|
None,
|
2021-09-29 16:35:20 +00:00
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2020-11-19 02:34:12 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
2022-10-10 19:40:42 +00:00
|
|
|
"instantaneous_demand",
|
2020-11-19 02:34:12 +00:00
|
|
|
async_test_metering,
|
2024-01-24 12:56:49 +00:00
|
|
|
10,
|
2020-11-19 02:34:12 +00:00
|
|
|
{
|
|
|
|
"demand_formatting": 0xF9,
|
|
|
|
"divisor": 1,
|
2021-09-29 16:35:20 +00:00
|
|
|
"metering_device_type": 0x00,
|
|
|
|
"multiplier": 1,
|
|
|
|
"status": 0x00,
|
|
|
|
},
|
2024-01-24 12:56:49 +00:00
|
|
|
{"current_summ_delivered", "current_summ_received"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
2022-10-10 19:40:42 +00:00
|
|
|
"summation_delivered",
|
2024-01-24 12:56:49 +00:00
|
|
|
async_test_smart_energy_summation_delivered,
|
|
|
|
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_received"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2024-01-24 12:56:49 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
|
|
|
"summation_received",
|
|
|
|
async_test_smart_energy_summation_received,
|
|
|
|
10,
|
2021-09-29 16:35:20 +00:00
|
|
|
{
|
|
|
|
"demand_formatting": 0xF9,
|
|
|
|
"divisor": 1000,
|
|
|
|
"metering_device_type": 0x00,
|
2020-11-19 02:34:12 +00:00
|
|
|
"multiplier": 1,
|
2021-09-29 16:35:20 +00:00
|
|
|
"status": 0x00,
|
2022-03-31 15:26:27 +00:00
|
|
|
"summation_formatting": 0b1_0111_010,
|
2024-01-16 23:40:00 +00:00
|
|
|
"unit_of_measure": 0x00,
|
2024-02-06 00:12:56 +00:00
|
|
|
"current_summ_received": 0,
|
2020-11-19 02:34:12 +00:00
|
|
|
},
|
2024-01-24 12:56:49 +00:00
|
|
|
{"instaneneous_demand", "current_summ_delivered"},
|
2024-02-06 00:12:56 +00:00
|
|
|
"0.0",
|
2020-11-19 02:34:12 +00:00
|
|
|
),
|
2020-02-10 02:45:35 +00:00
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2023-10-17 19:59:49 +00:00
|
|
|
"power",
|
2020-02-10 02:45:35 +00:00
|
|
|
async_test_electrical_measurement,
|
2021-11-19 00:43:08 +00:00
|
|
|
7,
|
2021-10-03 01:57:49 +00:00
|
|
|
{"ac_power_divisor": 1000, "ac_power_multiplier": 1},
|
2021-11-19 00:43:08 +00:00
|
|
|
{"apparent_power", "rms_current", "rms_voltage"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-11-19 00:43:08 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2022-10-10 19:40:42 +00:00
|
|
|
"apparent_power",
|
2021-11-19 00:43:08 +00:00
|
|
|
async_test_em_apparent_power,
|
|
|
|
7,
|
|
|
|
{"ac_power_divisor": 1000, "ac_power_multiplier": 1},
|
|
|
|
{"active_power", "rms_current", "rms_voltage"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-10-03 01:57:49 +00:00
|
|
|
),
|
2024-01-30 22:11:18 +00:00
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
|
|
|
"power_factor",
|
|
|
|
async_test_em_power_factor,
|
|
|
|
7,
|
|
|
|
{"ac_power_divisor": 1000, "ac_power_multiplier": 1},
|
|
|
|
{"active_power", "apparent_power", "rms_current", "rms_voltage"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2024-01-30 22:11:18 +00:00
|
|
|
),
|
2021-10-03 01:57:49 +00:00
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2023-10-17 19:59:49 +00:00
|
|
|
"current",
|
2021-10-03 01:57:49 +00:00
|
|
|
async_test_em_rms_current,
|
2021-11-19 00:43:08 +00:00
|
|
|
7,
|
2021-10-03 01:57:49 +00:00
|
|
|
{"ac_current_divisor": 1000, "ac_current_multiplier": 1},
|
2021-11-19 00:43:08 +00:00
|
|
|
{"active_power", "apparent_power", "rms_voltage"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2021-10-03 01:57:49 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2023-10-17 19:59:49 +00:00
|
|
|
"voltage",
|
2021-10-03 01:57:49 +00:00
|
|
|
async_test_em_rms_voltage,
|
2021-11-19 00:43:08 +00:00
|
|
|
7,
|
2021-10-03 01:57:49 +00:00
|
|
|
{"ac_voltage_divisor": 10, "ac_voltage_multiplier": 1},
|
2021-11-19 00:43:08 +00:00
|
|
|
{"active_power", "apparent_power", "rms_current"},
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2020-11-19 02:34:12 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
general.PowerConfiguration.cluster_id,
|
2022-07-10 20:17:59 +00:00
|
|
|
"battery",
|
2020-11-19 02:34:12 +00:00
|
|
|
async_test_powerconfiguration,
|
|
|
|
2,
|
|
|
|
{
|
|
|
|
"battery_size": 4, # AAA
|
|
|
|
"battery_voltage": 29,
|
|
|
|
"battery_quantity": 3,
|
|
|
|
},
|
2021-09-29 16:35:20 +00:00
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2020-02-10 02:45:35 +00:00
|
|
|
),
|
2022-08-12 01:13:27 +00:00
|
|
|
(
|
|
|
|
general.PowerConfiguration.cluster_id,
|
|
|
|
"battery",
|
|
|
|
async_test_powerconfiguration2,
|
|
|
|
2,
|
|
|
|
{
|
|
|
|
"battery_size": 4, # AAA
|
|
|
|
"battery_voltage": 29,
|
|
|
|
"battery_quantity": 3,
|
|
|
|
},
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2022-08-12 01:13:27 +00:00
|
|
|
),
|
2022-01-23 14:37:01 +00:00
|
|
|
(
|
|
|
|
general.DeviceTemperature.cluster_id,
|
|
|
|
"device_temperature",
|
|
|
|
async_test_device_temperature,
|
|
|
|
1,
|
|
|
|
None,
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2022-01-23 14:37:01 +00:00
|
|
|
),
|
2024-01-31 02:26:19 +00:00
|
|
|
(
|
|
|
|
hvac.Thermostat.cluster_id,
|
|
|
|
"setpoint_change_source",
|
|
|
|
async_test_setpoint_change_source,
|
|
|
|
10,
|
|
|
|
None,
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2024-01-31 02:26:19 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
hvac.Thermostat.cluster_id,
|
|
|
|
"pi_heating_demand",
|
|
|
|
async_test_pi_heating_demand,
|
|
|
|
10,
|
|
|
|
None,
|
|
|
|
None,
|
2024-02-06 00:12:56 +00:00
|
|
|
STATE_UNKNOWN,
|
2024-01-31 02:26:19 +00:00
|
|
|
),
|
2024-03-19 08:01:07 +00:00
|
|
|
],
|
2020-02-10 02:45:35 +00:00
|
|
|
)
|
|
|
|
async def test_sensor(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2020-02-10 02:45:35 +00:00
|
|
|
zigpy_device_mock,
|
|
|
|
zha_device_joined_restored,
|
|
|
|
cluster_id,
|
2021-09-29 16:35:20 +00:00
|
|
|
entity_suffix,
|
2020-02-10 02:45:35 +00:00
|
|
|
test_func,
|
|
|
|
report_count,
|
2020-11-19 02:34:12 +00:00
|
|
|
read_plug,
|
2021-09-29 16:35:20 +00:00
|
|
|
unsupported_attrs,
|
2024-02-06 00:12:56 +00:00
|
|
|
initial_sensor_state,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA sensor platform."""
|
2020-02-10 02:45:35 +00:00
|
|
|
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
2021-09-06 23:00:06 +00:00
|
|
|
SIG_EP_INPUT: [cluster_id, general.Basic.cluster_id],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
|
2020-02-10 02:45:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
cluster = zigpy_device.endpoints[1].in_clusters[cluster_id]
|
2021-09-29 16:35:20 +00:00
|
|
|
if unsupported_attrs:
|
|
|
|
for attr in unsupported_attrs:
|
|
|
|
cluster.add_unsupported_attribute(attr)
|
2021-10-03 01:57:49 +00:00
|
|
|
if cluster_id in (
|
|
|
|
smartenergy.Metering.cluster_id,
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
|
|
|
):
|
2020-11-19 02:34:12 +00:00
|
|
|
# this one is mains powered
|
|
|
|
zigpy_device.node_desc.mac_capability_flags |= 0b_0000_0100
|
|
|
|
cluster.PLUGGED_ATTR_READS = read_plug
|
2020-02-10 02:45:35 +00:00
|
|
|
zha_device = await zha_device_joined_restored(zigpy_device)
|
2022-10-10 19:40:42 +00:00
|
|
|
entity_id = ENTITY_ID_PREFIX.format(entity_suffix)
|
2020-01-18 01:53:31 +00:00
|
|
|
|
2020-06-11 21:21:08 +00:00
|
|
|
await async_enable_traffic(hass, [zha_device], enabled=False)
|
|
|
|
await hass.async_block_till_done()
|
2020-02-10 02:45:35 +00:00
|
|
|
# ensure the sensor entity was created
|
|
|
|
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
|
|
|
|
|
|
|
# allow traffic to flow through the gateway and devices
|
2020-02-12 21:12:14 +00:00
|
|
|
await async_enable_traffic(hass, [zha_device])
|
2020-02-10 02:45:35 +00:00
|
|
|
|
2024-02-06 00:12:56 +00:00
|
|
|
# test that the sensor now have their correct initial state (mostly unknown)
|
|
|
|
assert hass.states.get(entity_id).state == initial_sensor_state
|
2020-02-10 02:45:35 +00:00
|
|
|
|
|
|
|
# test sensor associated logic
|
|
|
|
await test_func(hass, cluster, entity_id)
|
|
|
|
|
|
|
|
# test rejoin
|
2020-02-12 21:12:14 +00:00
|
|
|
await async_test_rejoin(hass, zigpy_device, [cluster], (report_count,))
|
2019-02-03 21:03:35 +00:00
|
|
|
|
|
|
|
|
2024-01-24 12:56:49 +00:00
|
|
|
def assert_state(hass: HomeAssistant, entity_id, state, unit_of_measurement):
|
2019-02-03 21:03:35 +00:00
|
|
|
"""Check that the state is what is expected.
|
|
|
|
|
|
|
|
This is used to ensure that the logic in each sensor class handled the
|
|
|
|
attribute report it received correctly.
|
|
|
|
"""
|
2020-02-10 02:45:35 +00:00
|
|
|
hass_state = hass.states.get(entity_id)
|
2019-02-03 21:03:35 +00:00
|
|
|
assert hass_state.state == state
|
2020-01-11 01:30:58 +00:00
|
|
|
assert hass_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == unit_of_measurement
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2024-01-24 12:56:49 +00:00
|
|
|
def hass_ms(hass: HomeAssistant):
|
2020-01-11 01:30:58 +00:00
|
|
|
"""Hass instance with measurement system."""
|
|
|
|
|
|
|
|
async def _hass_ms(meas_sys):
|
|
|
|
await config_util.async_process_ha_core_config(
|
|
|
|
hass, {CONF_UNIT_SYSTEM: meas_sys}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
return hass
|
|
|
|
|
|
|
|
return _hass_ms
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def core_rs(hass_storage):
|
|
|
|
"""Core.restore_state fixture."""
|
|
|
|
|
|
|
|
def _storage(entity_id, uom, state):
|
|
|
|
now = dt_util.utcnow().isoformat()
|
|
|
|
|
|
|
|
hass_storage[restore_state.STORAGE_KEY] = {
|
|
|
|
"version": restore_state.STORAGE_VERSION,
|
|
|
|
"key": restore_state.STORAGE_KEY,
|
|
|
|
"data": [
|
|
|
|
{
|
|
|
|
"state": {
|
|
|
|
"entity_id": entity_id,
|
|
|
|
"state": str(state),
|
|
|
|
"attributes": {ATTR_UNIT_OF_MEASUREMENT: uom},
|
|
|
|
"last_changed": now,
|
|
|
|
"last_updated": now,
|
|
|
|
"context": {
|
|
|
|
"id": "3c2243ff5f30447eb12e7348cfd5b8ff",
|
|
|
|
"user_id": None,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"last_seen": now,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
|
|
|
|
return _storage
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2023-02-15 13:09:50 +00:00
|
|
|
("uom", "raw_temp", "expected", "restore"),
|
2020-01-11 01:30:58 +00:00
|
|
|
[
|
2023-01-15 18:14:02 +00:00
|
|
|
(UnitOfTemperature.CELSIUS, 2900, 29, False),
|
|
|
|
(UnitOfTemperature.CELSIUS, 2900, 29, True),
|
|
|
|
(UnitOfTemperature.FAHRENHEIT, 2900, 84, False),
|
|
|
|
(UnitOfTemperature.FAHRENHEIT, 2900, 84, True),
|
2020-01-11 01:30:58 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
async def test_temp_uom(
|
2023-05-31 01:48:17 +00:00
|
|
|
hass: HomeAssistant,
|
2020-02-10 02:45:35 +00:00
|
|
|
uom,
|
|
|
|
raw_temp,
|
|
|
|
expected,
|
|
|
|
restore,
|
|
|
|
hass_ms,
|
|
|
|
core_rs,
|
|
|
|
zigpy_device_mock,
|
|
|
|
zha_device_restored,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA temperature sensor unit of measurement."""
|
2020-01-11 01:30:58 +00:00
|
|
|
|
|
|
|
entity_id = "sensor.fake1026_fakemodel1026_004f3202_temperature"
|
|
|
|
if restore:
|
|
|
|
core_rs(entity_id, uom, state=(expected - 2))
|
2023-05-31 01:48:17 +00:00
|
|
|
await async_mock_load_restore_state_from_storage(hass)
|
2020-01-11 01:30:58 +00:00
|
|
|
|
|
|
|
hass = await hass_ms(
|
2023-01-15 18:14:02 +00:00
|
|
|
CONF_UNIT_SYSTEM_METRIC
|
|
|
|
if uom == UnitOfTemperature.CELSIUS
|
|
|
|
else CONF_UNIT_SYSTEM_IMPERIAL
|
2020-01-11 01:30:58 +00:00
|
|
|
)
|
|
|
|
|
2020-02-10 02:45:35 +00:00
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
2021-09-06 23:00:06 +00:00
|
|
|
SIG_EP_INPUT: [
|
2020-02-10 02:45:35 +00:00
|
|
|
measurement.TemperatureMeasurement.cluster_id,
|
|
|
|
general.Basic.cluster_id,
|
|
|
|
],
|
2021-09-06 23:00:06 +00:00
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
|
2020-02-10 02:45:35 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-11 01:30:58 +00:00
|
|
|
)
|
2020-02-10 02:45:35 +00:00
|
|
|
cluster = zigpy_device.endpoints[1].temperature
|
|
|
|
zha_device = await zha_device_restored(zigpy_device)
|
2023-06-15 01:42:31 +00:00
|
|
|
entity_id = find_entity_id(Platform.SENSOR, zha_device, hass)
|
2020-01-11 01:30:58 +00:00
|
|
|
|
|
|
|
if not restore:
|
2020-06-11 21:21:08 +00:00
|
|
|
await async_enable_traffic(hass, [zha_device], enabled=False)
|
2020-01-11 01:30:58 +00:00
|
|
|
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
|
|
|
|
|
|
|
# allow traffic to flow through the gateway and devices
|
2020-02-12 21:12:14 +00:00
|
|
|
await async_enable_traffic(hass, [zha_device])
|
2020-01-11 01:30:58 +00:00
|
|
|
|
|
|
|
# test that the sensors now have a state of unknown
|
|
|
|
if not restore:
|
|
|
|
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
|
|
|
|
2020-02-10 02:45:35 +00:00
|
|
|
await send_attribute_report(hass, cluster, 0, raw_temp)
|
2020-01-11 01:30:58 +00:00
|
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state is not None
|
|
|
|
assert round(float(state.state)) == expected
|
|
|
|
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == uom
|
2020-07-16 20:25:42 +00:00
|
|
|
|
|
|
|
|
2023-05-01 16:32:40 +00:00
|
|
|
@patch(
|
|
|
|
"zigpy.zcl.ClusterPersistingListener",
|
|
|
|
MagicMock(),
|
|
|
|
)
|
2020-07-16 20:25:42 +00:00
|
|
|
async def test_electrical_measurement_init(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2020-08-27 11:56:20 +00:00
|
|
|
zigpy_device_mock,
|
|
|
|
zha_device_joined,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2020-07-16 20:25:42 +00:00
|
|
|
"""Test proper initialization of the electrical measurement cluster."""
|
|
|
|
|
|
|
|
cluster_id = homeautomation.ElectricalMeasurement.cluster_id
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
2021-09-06 23:00:06 +00:00
|
|
|
SIG_EP_INPUT: [cluster_id, general.Basic.cluster_id],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
|
2020-07-16 20:25:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
cluster = zigpy_device.endpoints[1].in_clusters[cluster_id]
|
|
|
|
zha_device = await zha_device_joined(zigpy_device)
|
2023-10-17 19:59:49 +00:00
|
|
|
entity_id = "sensor.fakemanufacturer_fakemodel_power"
|
2020-07-16 20:25:42 +00:00
|
|
|
|
|
|
|
# allow traffic to flow through the gateway and devices
|
|
|
|
await async_enable_traffic(hass, [zha_device])
|
|
|
|
|
|
|
|
# test that the sensor now have a state of unknown
|
|
|
|
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 100, 10: 1000})
|
|
|
|
assert int(hass.states.get(entity_id).state) == 100
|
|
|
|
|
2023-04-19 14:47:07 +00:00
|
|
|
cluster_handler = zha_device._endpoints[1].all_cluster_handlers["1:0x0b04"]
|
|
|
|
assert cluster_handler.ac_power_divisor == 1
|
|
|
|
assert cluster_handler.ac_power_multiplier == 1
|
2020-07-16 20:25:42 +00:00
|
|
|
|
|
|
|
# update power divisor
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0403: 5, 10: 1000})
|
2023-04-19 14:47:07 +00:00
|
|
|
assert cluster_handler.ac_power_divisor == 5
|
|
|
|
assert cluster_handler.ac_power_multiplier == 1
|
2020-07-16 20:25:42 +00:00
|
|
|
assert hass.states.get(entity_id).state == "4.0"
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0605: 10, 10: 1000})
|
2023-04-19 14:47:07 +00:00
|
|
|
assert cluster_handler.ac_power_divisor == 10
|
|
|
|
assert cluster_handler.ac_power_multiplier == 1
|
2020-07-16 20:25:42 +00:00
|
|
|
assert hass.states.get(entity_id).state == "3.0"
|
|
|
|
|
|
|
|
# update power multiplier
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0402: 6, 10: 1000})
|
2023-04-19 14:47:07 +00:00
|
|
|
assert cluster_handler.ac_power_divisor == 10
|
|
|
|
assert cluster_handler.ac_power_multiplier == 6
|
2020-07-16 20:25:42 +00:00
|
|
|
assert hass.states.get(entity_id).state == "12.0"
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0604: 20, 10: 1000})
|
2023-04-19 14:47:07 +00:00
|
|
|
assert cluster_handler.ac_power_divisor == 10
|
|
|
|
assert cluster_handler.ac_power_multiplier == 20
|
2020-07-16 20:25:42 +00:00
|
|
|
assert hass.states.get(entity_id).state == "60.0"
|
2021-09-29 16:35:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2023-02-15 13:09:50 +00:00
|
|
|
("cluster_id", "unsupported_attributes", "entity_ids", "missing_entity_ids"),
|
2024-03-19 08:01:07 +00:00
|
|
|
[
|
2021-10-03 01:57:49 +00:00
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2021-11-19 00:43:08 +00:00
|
|
|
{"apparent_power", "rms_voltage", "rms_current"},
|
2022-04-24 16:42:52 +00:00
|
|
|
{
|
2023-10-17 19:59:49 +00:00
|
|
|
"power",
|
2022-10-10 19:40:42 +00:00
|
|
|
"ac_frequency",
|
|
|
|
"power_factor",
|
2022-04-24 16:42:52 +00:00
|
|
|
},
|
2021-10-03 01:57:49 +00:00
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"apparent_power",
|
2023-10-17 19:59:49 +00:00
|
|
|
"voltage",
|
|
|
|
"current",
|
2021-10-03 01:57:49 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
2022-04-24 16:42:52 +00:00
|
|
|
{"apparent_power", "rms_current", "ac_frequency", "power_factor"},
|
2023-10-17 19:59:49 +00:00
|
|
|
{"voltage", "power"},
|
2021-11-19 00:43:08 +00:00
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"apparent_power",
|
2023-10-17 19:59:49 +00:00
|
|
|
"current",
|
2022-10-10 19:40:42 +00:00
|
|
|
"ac_frequency",
|
|
|
|
"power_factor",
|
2021-11-19 00:43:08 +00:00
|
|
|
},
|
2021-10-03 01:57:49 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
homeautomation.ElectricalMeasurement.cluster_id,
|
|
|
|
set(),
|
|
|
|
{
|
2023-10-17 19:59:49 +00:00
|
|
|
"voltage",
|
|
|
|
"power",
|
2022-10-10 19:40:42 +00:00
|
|
|
"apparent_power",
|
2023-10-17 19:59:49 +00:00
|
|
|
"current",
|
2022-10-10 19:40:42 +00:00
|
|
|
"ac_frequency",
|
|
|
|
"power_factor",
|
2021-10-03 01:57:49 +00:00
|
|
|
},
|
|
|
|
set(),
|
|
|
|
),
|
2021-09-29 16:35:20 +00:00
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
|
|
|
{
|
|
|
|
"instantaneous_demand",
|
|
|
|
},
|
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"summation_delivered",
|
2021-09-29 16:35:20 +00:00
|
|
|
},
|
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"instantaneous_demand",
|
2021-09-29 16:35:20 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
2024-02-06 00:12:56 +00:00
|
|
|
{"instantaneous_demand", "current_summ_delivered"},
|
2021-09-29 16:35:20 +00:00
|
|
|
{},
|
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"instantaneous_demand",
|
2024-01-24 12:56:49 +00:00
|
|
|
"summation_delivered",
|
2021-09-29 16:35:20 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
smartenergy.Metering.cluster_id,
|
|
|
|
{},
|
|
|
|
{
|
2022-10-10 19:40:42 +00:00
|
|
|
"instantaneous_demand",
|
2024-01-24 12:56:49 +00:00
|
|
|
"summation_delivered",
|
2021-09-29 16:35:20 +00:00
|
|
|
},
|
|
|
|
{},
|
|
|
|
),
|
2024-03-19 08:01:07 +00:00
|
|
|
],
|
2021-09-29 16:35:20 +00:00
|
|
|
)
|
|
|
|
async def test_unsupported_attributes_sensor(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2021-09-29 16:35:20 +00:00
|
|
|
zigpy_device_mock,
|
|
|
|
zha_device_joined_restored,
|
|
|
|
cluster_id,
|
|
|
|
unsupported_attributes,
|
|
|
|
entity_ids,
|
|
|
|
missing_entity_ids,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA sensor platform."""
|
2021-09-29 16:35:20 +00:00
|
|
|
|
2022-10-10 19:40:42 +00:00
|
|
|
entity_ids = {ENTITY_ID_PREFIX.format(e) for e in entity_ids}
|
|
|
|
missing_entity_ids = {ENTITY_ID_PREFIX.format(e) for e in missing_entity_ids}
|
2021-09-29 16:35:20 +00:00
|
|
|
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
|
|
|
SIG_EP_INPUT: [cluster_id, general.Basic.cluster_id],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.ON_OFF_SWITCH,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
cluster = zigpy_device.endpoints[1].in_clusters[cluster_id]
|
|
|
|
if cluster_id == smartenergy.Metering.cluster_id:
|
|
|
|
# this one is mains powered
|
|
|
|
zigpy_device.node_desc.mac_capability_flags |= 0b_0000_0100
|
|
|
|
for attr in unsupported_attributes:
|
|
|
|
cluster.add_unsupported_attribute(attr)
|
|
|
|
zha_device = await zha_device_joined_restored(zigpy_device)
|
|
|
|
|
|
|
|
await async_enable_traffic(hass, [zha_device], enabled=False)
|
|
|
|
await hass.async_block_till_done()
|
2022-07-10 20:17:59 +00:00
|
|
|
present_entity_ids = set(find_entity_ids(Platform.SENSOR, zha_device, hass))
|
2021-09-29 16:35:20 +00:00
|
|
|
assert present_entity_ids == entity_ids
|
|
|
|
assert missing_entity_ids not in present_entity_ids
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2023-02-15 13:09:50 +00:00
|
|
|
("raw_uom", "raw_value", "expected_state", "expected_uom"),
|
2024-03-19 08:01:07 +00:00
|
|
|
[
|
2021-09-29 16:35:20 +00:00
|
|
|
(
|
|
|
|
1,
|
|
|
|
12320,
|
|
|
|
"1.23",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfVolume.CUBIC_METERS,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
1,
|
|
|
|
1232000,
|
2024-01-16 23:40:00 +00:00
|
|
|
"123.2",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfVolume.CUBIC_METERS,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
3,
|
|
|
|
2340,
|
2024-01-16 23:40:00 +00:00
|
|
|
"0.65",
|
|
|
|
UnitOfVolume.CUBIC_METERS,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
3,
|
|
|
|
2360,
|
2024-01-16 23:40:00 +00:00
|
|
|
"0.68",
|
|
|
|
UnitOfVolume.CUBIC_METERS,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
8,
|
|
|
|
23660,
|
|
|
|
"2.37",
|
2024-01-16 23:40:00 +00:00
|
|
|
UnitOfPressure.KPA,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
9366,
|
|
|
|
"0.937",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
999,
|
|
|
|
"0.1",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
10091,
|
|
|
|
"1.009",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
10099,
|
|
|
|
"1.01",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
100999,
|
|
|
|
"10.1",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
100023,
|
|
|
|
"10.002",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
0,
|
|
|
|
102456,
|
|
|
|
"10.246",
|
2023-01-15 18:14:02 +00:00
|
|
|
UnitOfEnergy.KILO_WATT_HOUR,
|
2021-09-29 16:35:20 +00:00
|
|
|
),
|
2024-01-16 23:40:00 +00:00
|
|
|
(
|
|
|
|
5,
|
|
|
|
102456,
|
|
|
|
"10.25",
|
|
|
|
"IMP gal",
|
|
|
|
),
|
|
|
|
(
|
|
|
|
7,
|
|
|
|
50124,
|
|
|
|
"5.01",
|
|
|
|
UnitOfVolume.LITERS,
|
|
|
|
),
|
2024-03-19 08:01:07 +00:00
|
|
|
],
|
2021-09-29 16:35:20 +00:00
|
|
|
)
|
|
|
|
async def test_se_summation_uom(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2021-09-29 16:35:20 +00:00
|
|
|
zigpy_device_mock,
|
|
|
|
zha_device_joined,
|
|
|
|
raw_uom,
|
|
|
|
raw_value,
|
|
|
|
expected_state,
|
|
|
|
expected_uom,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA smart energy summation."""
|
2021-09-29 16:35:20 +00:00
|
|
|
|
2022-10-10 19:40:42 +00:00
|
|
|
entity_id = ENTITY_ID_PREFIX.format("summation_delivered")
|
2021-09-29 16:35:20 +00:00
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
|
|
|
SIG_EP_INPUT: [
|
|
|
|
smartenergy.Metering.cluster_id,
|
|
|
|
general.Basic.cluster_id,
|
|
|
|
],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.SIMPLE_SENSOR,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
zigpy_device.node_desc.mac_capability_flags |= 0b_0000_0100
|
|
|
|
|
|
|
|
cluster = zigpy_device.endpoints[1].in_clusters[smartenergy.Metering.cluster_id]
|
|
|
|
for attr in ("instanteneous_demand",):
|
|
|
|
cluster.add_unsupported_attribute(attr)
|
|
|
|
cluster.PLUGGED_ATTR_READS = {
|
|
|
|
"current_summ_delivered": raw_value,
|
|
|
|
"demand_formatting": 0xF9,
|
|
|
|
"divisor": 10000,
|
|
|
|
"metering_device_type": 0x00,
|
|
|
|
"multiplier": 1,
|
|
|
|
"status": 0x00,
|
2022-03-31 15:26:27 +00:00
|
|
|
"summation_formatting": 0b1_0111_010,
|
2021-09-29 16:35:20 +00:00
|
|
|
"unit_of_measure": raw_uom,
|
|
|
|
}
|
|
|
|
await zha_device_joined(zigpy_device)
|
|
|
|
|
|
|
|
assert_state(hass, entity_id, expected_state, expected_uom)
|
2021-10-03 01:57:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2023-02-15 13:09:50 +00:00
|
|
|
("raw_measurement_type", "expected_type"),
|
2024-03-19 08:01:07 +00:00
|
|
|
[
|
2021-10-03 01:57:49 +00:00
|
|
|
(1, "ACTIVE_MEASUREMENT"),
|
|
|
|
(8, "PHASE_A_MEASUREMENT"),
|
|
|
|
(9, "ACTIVE_MEASUREMENT, PHASE_A_MEASUREMENT"),
|
|
|
|
(
|
|
|
|
15,
|
2023-01-26 00:23:53 +00:00
|
|
|
(
|
|
|
|
"ACTIVE_MEASUREMENT, REACTIVE_MEASUREMENT, APPARENT_MEASUREMENT,"
|
|
|
|
" PHASE_A_MEASUREMENT"
|
|
|
|
),
|
2021-10-03 01:57:49 +00:00
|
|
|
),
|
2024-03-19 08:01:07 +00:00
|
|
|
],
|
2021-10-03 01:57:49 +00:00
|
|
|
)
|
|
|
|
async def test_elec_measurement_sensor_type(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2021-10-03 01:57:49 +00:00
|
|
|
elec_measurement_zigpy_dev,
|
|
|
|
raw_measurement_type,
|
|
|
|
expected_type,
|
|
|
|
zha_device_joined,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA electrical measurement sensor type."""
|
2021-10-03 01:57:49 +00:00
|
|
|
|
2023-10-17 19:59:49 +00:00
|
|
|
entity_id = ENTITY_ID_PREFIX.format("power")
|
2021-10-03 01:57:49 +00:00
|
|
|
zigpy_dev = elec_measurement_zigpy_dev
|
|
|
|
zigpy_dev.endpoints[1].electrical_measurement.PLUGGED_ATTR_READS[
|
|
|
|
"measurement_type"
|
|
|
|
] = raw_measurement_type
|
|
|
|
|
|
|
|
await zha_device_joined(zigpy_dev)
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state is not None
|
|
|
|
assert state.attributes["measurement_type"] == expected_type
|
|
|
|
|
|
|
|
|
2023-12-27 15:25:41 +00:00
|
|
|
async def test_elec_measurement_sensor_polling(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
elec_measurement_zigpy_dev,
|
|
|
|
zha_device_joined_restored,
|
|
|
|
) -> None:
|
|
|
|
"""Test ZHA electrical measurement sensor polling."""
|
|
|
|
|
|
|
|
entity_id = ENTITY_ID_PREFIX.format("power")
|
|
|
|
zigpy_dev = elec_measurement_zigpy_dev
|
2024-03-25 23:02:16 +00:00
|
|
|
zigpy_dev.endpoints[1].electrical_measurement.PLUGGED_ATTR_READS["active_power"] = (
|
|
|
|
20
|
|
|
|
)
|
2023-12-27 15:25:41 +00:00
|
|
|
|
|
|
|
await zha_device_joined_restored(zigpy_dev)
|
|
|
|
|
|
|
|
# test that the sensor has an initial state of 2.0
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state.state == "2.0"
|
|
|
|
|
|
|
|
# update the value for the power reading
|
2024-03-25 23:02:16 +00:00
|
|
|
zigpy_dev.endpoints[1].electrical_measurement.PLUGGED_ATTR_READS["active_power"] = (
|
|
|
|
60
|
|
|
|
)
|
2023-12-27 15:25:41 +00:00
|
|
|
|
|
|
|
# ensure the state is still 2.0
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state.state == "2.0"
|
|
|
|
|
|
|
|
# let the polling happen
|
|
|
|
future = dt_util.utcnow() + timedelta(seconds=90)
|
|
|
|
async_fire_time_changed(hass, future)
|
2024-03-09 02:45:10 +00:00
|
|
|
await hass.async_block_till_done(wait_background_tasks=True)
|
2023-12-27 15:25:41 +00:00
|
|
|
|
|
|
|
# ensure the state has been updated to 6.0
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state.state == "6.0"
|
|
|
|
|
|
|
|
|
2021-10-03 01:57:49 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"supported_attributes",
|
2024-03-19 08:01:07 +00:00
|
|
|
[
|
2021-10-03 01:57:49 +00:00
|
|
|
set(),
|
|
|
|
{
|
|
|
|
"active_power",
|
|
|
|
"active_power_max",
|
|
|
|
"rms_current",
|
|
|
|
"rms_current_max",
|
|
|
|
"rms_voltage",
|
|
|
|
"rms_voltage_max",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"active_power",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"active_power",
|
|
|
|
"active_power_max",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"rms_current",
|
|
|
|
"rms_current_max",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"rms_voltage",
|
|
|
|
"rms_voltage_max",
|
|
|
|
},
|
2024-03-19 08:01:07 +00:00
|
|
|
],
|
2021-10-03 01:57:49 +00:00
|
|
|
)
|
|
|
|
async def test_elec_measurement_skip_unsupported_attribute(
|
2023-02-17 17:54:26 +00:00
|
|
|
hass: HomeAssistant,
|
2021-10-03 01:57:49 +00:00
|
|
|
elec_measurement_zha_dev,
|
|
|
|
supported_attributes,
|
2023-02-17 17:54:26 +00:00
|
|
|
) -> None:
|
2023-01-02 05:20:59 +00:00
|
|
|
"""Test ZHA electrical measurement skipping update of unsupported attributes."""
|
2021-10-03 01:57:49 +00:00
|
|
|
|
2023-10-17 19:59:49 +00:00
|
|
|
entity_id = ENTITY_ID_PREFIX.format("power")
|
2021-10-03 01:57:49 +00:00
|
|
|
zha_dev = elec_measurement_zha_dev
|
|
|
|
|
|
|
|
cluster = zha_dev.device.endpoints[1].electrical_measurement
|
|
|
|
|
|
|
|
all_attrs = {
|
|
|
|
"active_power",
|
|
|
|
"active_power_max",
|
2021-11-19 00:43:08 +00:00
|
|
|
"apparent_power",
|
2021-10-03 01:57:49 +00:00
|
|
|
"rms_current",
|
|
|
|
"rms_current_max",
|
|
|
|
"rms_voltage",
|
|
|
|
"rms_voltage_max",
|
2022-04-24 16:42:52 +00:00
|
|
|
"power_factor",
|
|
|
|
"ac_frequency",
|
|
|
|
"ac_frequency_max",
|
2021-10-03 01:57:49 +00:00
|
|
|
}
|
|
|
|
for attr in all_attrs - supported_attributes:
|
|
|
|
cluster.add_unsupported_attribute(attr)
|
|
|
|
cluster.read_attributes.reset_mock()
|
|
|
|
|
|
|
|
await async_update_entity(hass, entity_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert cluster.read_attributes.call_count == math.ceil(
|
2023-04-19 14:47:07 +00:00
|
|
|
len(supported_attributes) / ZHA_CLUSTER_HANDLER_READS_PER_REQ
|
2021-10-03 01:57:49 +00:00
|
|
|
)
|
|
|
|
read_attrs = {
|
|
|
|
a for call in cluster.read_attributes.call_args_list for a in call[0][0]
|
|
|
|
}
|
|
|
|
assert read_attrs == supported_attributes
|
2024-02-23 18:22:47 +00:00
|
|
|
|
|
|
|
|
2024-02-29 15:38:21 +00:00
|
|
|
class OppleCluster(CustomCluster, ManufacturerSpecificCluster):
|
|
|
|
"""Aqara manufacturer specific cluster."""
|
|
|
|
|
|
|
|
cluster_id = 0xFCC0
|
|
|
|
ep_attribute = "opple_cluster"
|
|
|
|
attributes = {
|
|
|
|
0x010C: ("last_feeding_size", t.uint16_t, True),
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs) -> None:
|
|
|
|
"""Initialize."""
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# populate cache to create config entity
|
|
|
|
self._attr_cache.update({0x010C: 10})
|
|
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
add_to_registry_v2("Fake_Manufacturer_sensor", "Fake_Model_sensor")
|
|
|
|
.replaces(OppleCluster)
|
|
|
|
.sensor(
|
|
|
|
"last_feeding_size",
|
|
|
|
OppleCluster.cluster_id,
|
|
|
|
divisor=1,
|
|
|
|
multiplier=1,
|
|
|
|
unit=UnitOfMass.GRAMS,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
async def zigpy_device_aqara_sensor_v2(
|
|
|
|
hass: HomeAssistant, zigpy_device_mock, zha_device_joined_restored
|
|
|
|
):
|
|
|
|
"""Device tracker zigpy Aqara motion sensor device."""
|
|
|
|
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
|
|
|
SIG_EP_INPUT: [
|
|
|
|
general.Basic.cluster_id,
|
|
|
|
OppleCluster.cluster_id,
|
|
|
|
],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.OCCUPANCY_SENSOR,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
manufacturer="Fake_Manufacturer_sensor",
|
|
|
|
model="Fake_Model_sensor",
|
|
|
|
)
|
|
|
|
|
|
|
|
zha_device = await zha_device_joined_restored(zigpy_device)
|
|
|
|
return zha_device, zigpy_device.endpoints[1].opple_cluster
|
|
|
|
|
|
|
|
|
|
|
|
async def test_last_feeding_size_sensor_v2(
|
|
|
|
hass: HomeAssistant, zigpy_device_aqara_sensor_v2
|
|
|
|
) -> None:
|
|
|
|
"""Test quirks defined sensor."""
|
|
|
|
|
|
|
|
zha_device, cluster = zigpy_device_aqara_sensor_v2
|
|
|
|
assert isinstance(zha_device.device, CustomDeviceV2)
|
|
|
|
entity_id = find_entity_id(
|
|
|
|
Platform.SENSOR, zha_device, hass, qualifier="last_feeding_size"
|
|
|
|
)
|
|
|
|
assert entity_id is not None
|
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0x010C: 1})
|
2024-03-27 16:48:43 +00:00
|
|
|
assert_state(hass, entity_id, "1.0", UnitOfMass.GRAMS.value)
|
2024-02-29 15:38:21 +00:00
|
|
|
|
|
|
|
await send_attributes_report(hass, cluster, {0x010C: 5})
|
2024-03-27 16:48:43 +00:00
|
|
|
assert_state(hass, entity_id, "5.0", UnitOfMass.GRAMS.value)
|
2024-02-29 15:38:21 +00:00
|
|
|
|
|
|
|
|
2024-02-23 18:22:47 +00:00
|
|
|
@pytest.fixture
|
|
|
|
async def coordinator(hass: HomeAssistant, zigpy_device_mock, zha_device_joined):
|
|
|
|
"""Test ZHA fan platform."""
|
|
|
|
|
|
|
|
zigpy_device = zigpy_device_mock(
|
|
|
|
{
|
|
|
|
1: {
|
|
|
|
SIG_EP_INPUT: [general.Groups.cluster_id],
|
|
|
|
SIG_EP_OUTPUT: [],
|
|
|
|
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.CONTROL_BRIDGE,
|
|
|
|
SIG_EP_PROFILE: zigpy.profiles.zha.PROFILE_ID,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ieee="00:15:8d:00:02:32:4f:32",
|
|
|
|
nwk=0x0000,
|
|
|
|
node_descriptor=b"\xf8\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
|
|
|
|
)
|
|
|
|
zha_device = await zha_device_joined(zigpy_device)
|
|
|
|
zha_device.available = True
|
|
|
|
return zha_device
|
|
|
|
|
|
|
|
|
|
|
|
async def test_device_counter_sensors(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
coordinator: ZHADevice,
|
|
|
|
entity_registry: er.EntityRegistry,
|
|
|
|
config_entry: MockConfigEntry,
|
|
|
|
) -> None:
|
|
|
|
"""Test quirks defined sensor."""
|
|
|
|
|
|
|
|
entity_id = "sensor.coordinator_manufacturer_coordinator_model_counter_1"
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state is None
|
|
|
|
|
|
|
|
# Enable the entity.
|
|
|
|
entity_registry.async_update_entity(entity_id, disabled_by=None)
|
|
|
|
await hass.config_entries.async_reload(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state is not None
|
|
|
|
assert state.state == "1"
|
|
|
|
|
|
|
|
# simulate counter increment on application
|
|
|
|
coordinator.device.application.state.counters["ezsp_counters"][
|
|
|
|
"counter_1"
|
|
|
|
].increment()
|
|
|
|
|
|
|
|
next_update = dt_util.utcnow() + timedelta(seconds=60)
|
|
|
|
async_fire_time_changed(hass, next_update)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state is not None
|
|
|
|
assert state.state == "2"
|