mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add support for Energy Production CC sensors (#93839)
This commit is contained in:
parent
c72477811e
commit
1eb1ea08b0
@ -133,6 +133,11 @@ ENTITY_DESC_KEY_TARGET_TEMPERATURE = "target_temperature"
|
|||||||
ENTITY_DESC_KEY_MEASUREMENT = "measurement"
|
ENTITY_DESC_KEY_MEASUREMENT = "measurement"
|
||||||
ENTITY_DESC_KEY_TOTAL_INCREASING = "total_increasing"
|
ENTITY_DESC_KEY_TOTAL_INCREASING = "total_increasing"
|
||||||
|
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_POWER = "energy_production_power"
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME = "energy_production_time"
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL = "energy_production_total"
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY = "energy_production_today"
|
||||||
|
|
||||||
# This API key is only for use with Home Assistant. Reach out to Z-Wave JS to apply for
|
# This API key is only for use with Home Assistant. Reach out to Z-Wave JS to apply for
|
||||||
# your own (https://github.com/zwave-js/firmware-updates/).
|
# your own (https://github.com/zwave-js/firmware-updates/).
|
||||||
API_KEY_FIRMWARE_UPDATE_SERVICE = (
|
API_KEY_FIRMWARE_UPDATE_SERVICE = (
|
||||||
|
@ -722,9 +722,10 @@ DISCOVERY_SCHEMAS = [
|
|||||||
hint="numeric_sensor",
|
hint="numeric_sensor",
|
||||||
primary_value=ZWaveValueDiscoverySchema(
|
primary_value=ZWaveValueDiscoverySchema(
|
||||||
command_class={
|
command_class={
|
||||||
CommandClass.SENSOR_MULTILEVEL,
|
|
||||||
CommandClass.SENSOR_ALARM,
|
|
||||||
CommandClass.BATTERY,
|
CommandClass.BATTERY,
|
||||||
|
CommandClass.ENERGY_PRODUCTION,
|
||||||
|
CommandClass.SENSOR_ALARM,
|
||||||
|
CommandClass.SENSOR_MULTILEVEL,
|
||||||
},
|
},
|
||||||
type={ValueType.NUMBER},
|
type={ValueType.NUMBER},
|
||||||
),
|
),
|
||||||
|
@ -7,6 +7,14 @@ import logging
|
|||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from zwave_js_server.const import CommandClass
|
from zwave_js_server.const import CommandClass
|
||||||
|
from zwave_js_server.const.command_class.energy_production import (
|
||||||
|
EnergyProductionParameter,
|
||||||
|
EnergyProductionScaleType,
|
||||||
|
PowerScale,
|
||||||
|
TodaysProductionScale,
|
||||||
|
TotalProductionScale,
|
||||||
|
TotalTimeScale,
|
||||||
|
)
|
||||||
from zwave_js_server.const.command_class.meter import (
|
from zwave_js_server.const.command_class.meter import (
|
||||||
CURRENT_METER_TYPES,
|
CURRENT_METER_TYPES,
|
||||||
ENERGY_TOTAL_INCREASING_METER_TYPES,
|
ENERGY_TOTAL_INCREASING_METER_TYPES,
|
||||||
@ -85,6 +93,10 @@ from zwave_js_server.model.value import (
|
|||||||
Value as ZwaveValue,
|
Value as ZwaveValue,
|
||||||
get_value_id_str,
|
get_value_id_str,
|
||||||
)
|
)
|
||||||
|
from zwave_js_server.util.command_class.energy_production import (
|
||||||
|
get_energy_production_parameter,
|
||||||
|
get_energy_production_scale_type,
|
||||||
|
)
|
||||||
from zwave_js_server.util.command_class.meter import get_meter_scale_type
|
from zwave_js_server.util.command_class.meter import get_meter_scale_type
|
||||||
from zwave_js_server.util.command_class.multilevel_sensor import (
|
from zwave_js_server.util.command_class.multilevel_sensor import (
|
||||||
get_multilevel_sensor_scale_type,
|
get_multilevel_sensor_scale_type,
|
||||||
@ -123,6 +135,10 @@ from .const import (
|
|||||||
ENTITY_DESC_KEY_CO2,
|
ENTITY_DESC_KEY_CO2,
|
||||||
ENTITY_DESC_KEY_CURRENT,
|
ENTITY_DESC_KEY_CURRENT,
|
||||||
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
|
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_POWER,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL,
|
||||||
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
|
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
|
||||||
ENTITY_DESC_KEY_HUMIDITY,
|
ENTITY_DESC_KEY_HUMIDITY,
|
||||||
ENTITY_DESC_KEY_ILLUMINANCE,
|
ENTITY_DESC_KEY_ILLUMINANCE,
|
||||||
@ -138,6 +154,18 @@ from .const import (
|
|||||||
)
|
)
|
||||||
from .helpers import ZwaveValueID
|
from .helpers import ZwaveValueID
|
||||||
|
|
||||||
|
ENERGY_PRODUCTION_DEVICE_CLASS_MAP: dict[str, list[EnergyProductionParameter]] = {
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME: [EnergyProductionParameter.TOTAL_TIME],
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY: [
|
||||||
|
EnergyProductionParameter.TODAYS_PRODUCTION
|
||||||
|
],
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL: [
|
||||||
|
EnergyProductionParameter.TOTAL_PRODUCTION
|
||||||
|
],
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_POWER: [EnergyProductionParameter.POWER],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
METER_DEVICE_CLASS_MAP: dict[str, list[MeterScaleType]] = {
|
METER_DEVICE_CLASS_MAP: dict[str, list[MeterScaleType]] = {
|
||||||
ENTITY_DESC_KEY_CURRENT: CURRENT_METER_TYPES,
|
ENTITY_DESC_KEY_CURRENT: CURRENT_METER_TYPES,
|
||||||
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES,
|
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES,
|
||||||
@ -160,6 +188,16 @@ MULTILEVEL_SENSOR_DEVICE_CLASS_MAP: dict[str, list[MultilevelSensorType]] = {
|
|||||||
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_SENSORS,
|
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_SENSORS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENERGY_PRODUCTION_UNIT_MAP: dict[str, list[EnergyProductionScaleType]] = {
|
||||||
|
UnitOfEnergy.WATT_HOUR: [
|
||||||
|
TotalProductionScale.WATT_HOURS,
|
||||||
|
TodaysProductionScale.WATT_HOURS,
|
||||||
|
],
|
||||||
|
UnitOfPower.WATT: [PowerScale.WATTS],
|
||||||
|
UnitOfTime.SECONDS: [TotalTimeScale.SECONDS],
|
||||||
|
UnitOfTime.HOURS: [TotalTimeScale.HOURS],
|
||||||
|
}
|
||||||
|
|
||||||
METER_UNIT_MAP: dict[str, list[MeterScaleType]] = {
|
METER_UNIT_MAP: dict[str, list[MeterScaleType]] = {
|
||||||
UnitOfElectricCurrent.AMPERE: METER_UNIT_AMPERE,
|
UnitOfElectricCurrent.AMPERE: METER_UNIT_AMPERE,
|
||||||
UnitOfVolume.CUBIC_FEET: UNIT_CUBIC_FEET,
|
UnitOfVolume.CUBIC_FEET: UNIT_CUBIC_FEET,
|
||||||
@ -320,12 +358,18 @@ class NumericSensorDataTemplate(BaseDiscoverySchemaDataTemplate):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_key_from_matching_set(
|
def find_key_from_matching_set(
|
||||||
enum_value: MultilevelSensorType | MultilevelSensorScaleType | MeterScaleType,
|
enum_value: MultilevelSensorType
|
||||||
|
| MultilevelSensorScaleType
|
||||||
|
| MeterScaleType
|
||||||
|
| EnergyProductionParameter
|
||||||
|
| EnergyProductionScaleType,
|
||||||
set_map: Mapping[
|
set_map: Mapping[
|
||||||
str,
|
str,
|
||||||
list[MultilevelSensorType]
|
list[MultilevelSensorType]
|
||||||
| list[MultilevelSensorScaleType]
|
| list[MultilevelSensorScaleType]
|
||||||
| list[MeterScaleType],
|
| list[MeterScaleType]
|
||||||
|
| list[EnergyProductionScaleType]
|
||||||
|
| list[EnergyProductionParameter],
|
||||||
],
|
],
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Find a key in a set map that matches a given enum value."""
|
"""Find a key in a set map that matches a given enum value."""
|
||||||
@ -387,6 +431,18 @@ class NumericSensorDataTemplate(BaseDiscoverySchemaDataTemplate):
|
|||||||
if key:
|
if key:
|
||||||
return NumericSensorDataTemplateData(key, unit)
|
return NumericSensorDataTemplateData(key, unit)
|
||||||
|
|
||||||
|
if value.command_class == CommandClass.ENERGY_PRODUCTION:
|
||||||
|
energy_production_parameter = get_energy_production_parameter(value)
|
||||||
|
energy_production_scale_type = get_energy_production_scale_type(value)
|
||||||
|
unit = self.find_key_from_matching_set(
|
||||||
|
energy_production_scale_type, ENERGY_PRODUCTION_UNIT_MAP
|
||||||
|
)
|
||||||
|
key = self.find_key_from_matching_set(
|
||||||
|
energy_production_parameter, ENERGY_PRODUCTION_DEVICE_CLASS_MAP
|
||||||
|
)
|
||||||
|
if key:
|
||||||
|
return NumericSensorDataTemplateData(key, unit)
|
||||||
|
|
||||||
return NumericSensorDataTemplateData()
|
return NumericSensorDataTemplateData()
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,6 +58,10 @@ from .const import (
|
|||||||
ENTITY_DESC_KEY_CO2,
|
ENTITY_DESC_KEY_CO2,
|
||||||
ENTITY_DESC_KEY_CURRENT,
|
ENTITY_DESC_KEY_CURRENT,
|
||||||
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
|
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_POWER,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY,
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL,
|
||||||
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
|
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
|
||||||
ENTITY_DESC_KEY_HUMIDITY,
|
ENTITY_DESC_KEY_HUMIDITY,
|
||||||
ENTITY_DESC_KEY_ILLUMINANCE,
|
ENTITY_DESC_KEY_ILLUMINANCE,
|
||||||
@ -235,6 +239,50 @@ ENTITY_DESCRIPTION_KEY_DEVICE_CLASS_MAP: dict[
|
|||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
|
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME,
|
||||||
|
UnitOfTime.SECONDS,
|
||||||
|
): SensorEntityDescription(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME,
|
||||||
|
name="Energy production time",
|
||||||
|
device_class=SensorDeviceClass.DURATION,
|
||||||
|
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||||
|
),
|
||||||
|
(ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME, UnitOfTime.HOURS): SensorEntityDescription(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TIME,
|
||||||
|
device_class=SensorDeviceClass.DURATION,
|
||||||
|
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY,
|
||||||
|
UnitOfEnergy.WATT_HOUR,
|
||||||
|
): SensorEntityDescription(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TODAY,
|
||||||
|
name="Energy production today",
|
||||||
|
device_class=SensorDeviceClass.ENERGY,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL,
|
||||||
|
UnitOfEnergy.WATT_HOUR,
|
||||||
|
): SensorEntityDescription(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_TOTAL,
|
||||||
|
name="Energy production total",
|
||||||
|
device_class=SensorDeviceClass.ENERGY,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ENTITY_DESC_KEY_ENERGY_PRODUCTION_POWER,
|
||||||
|
UnitOfPower.WATT,
|
||||||
|
): SensorEntityDescription(
|
||||||
|
ENTITY_DESC_KEY_POWER,
|
||||||
|
name="Energy production power",
|
||||||
|
device_class=SensorDeviceClass.POWER,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=UnitOfPower.WATT,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# These descriptions are without device class.
|
# These descriptions are without device class.
|
||||||
@ -547,12 +595,13 @@ class ZwaveSensor(ZWaveBaseEntity, SensorEntity):
|
|||||||
unit_of_measurement: str | None = None,
|
unit_of_measurement: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a ZWaveSensorBase entity."""
|
"""Initialize a ZWaveSensorBase entity."""
|
||||||
super().__init__(config_entry, driver, info)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(config_entry, driver, info)
|
||||||
self._attr_native_unit_of_measurement = unit_of_measurement
|
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||||
|
|
||||||
# Entity class attributes
|
# Entity class attributes
|
||||||
self._attr_force_update = True
|
self._attr_force_update = True
|
||||||
|
if not entity_description.name:
|
||||||
self._attr_name = self.generate_name(include_value_name=True)
|
self._attr_name = self.generate_name(include_value_name=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -624,6 +624,12 @@ def indicator_test_state_fixture():
|
|||||||
return json.loads(load_fixture("zwave_js/indicator_test_state.json"))
|
return json.loads(load_fixture("zwave_js/indicator_test_state.json"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="energy_production_state", scope="session")
|
||||||
|
def energy_production_state_fixture():
|
||||||
|
"""Load a mock node with energy production CC state fixture data."""
|
||||||
|
return json.loads(load_fixture("zwave_js/energy_production_state.json"))
|
||||||
|
|
||||||
|
|
||||||
# model fixtures
|
# model fixtures
|
||||||
|
|
||||||
|
|
||||||
@ -1191,3 +1197,11 @@ def indicator_test_fixture(client, indicator_test_state):
|
|||||||
node = Node(client, copy.deepcopy(indicator_test_state))
|
node = Node(client, copy.deepcopy(indicator_test_state))
|
||||||
client.driver.controller.nodes[node.node_id] = node
|
client.driver.controller.nodes[node.node_id] = node
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="energy_production")
|
||||||
|
def energy_prodution_fixture(client, energy_production_state):
|
||||||
|
"""Mock a mock node with Energy Production CC."""
|
||||||
|
node = Node(client, copy.deepcopy(energy_production_state))
|
||||||
|
client.driver.controller.nodes[node.node_id] = node
|
||||||
|
return node
|
||||||
|
241
tests/components/zwave_js/fixtures/energy_production_state.json
Normal file
241
tests/components/zwave_js/fixtures/energy_production_state.json
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
{
|
||||||
|
"nodeId": 2,
|
||||||
|
"index": 0,
|
||||||
|
"status": 4,
|
||||||
|
"ready": true,
|
||||||
|
"isListening": true,
|
||||||
|
"isRouting": true,
|
||||||
|
"isSecure": false,
|
||||||
|
"interviewAttempts": 1,
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"nodeId": 2,
|
||||||
|
"index": 0,
|
||||||
|
"deviceClass": {
|
||||||
|
"basic": {
|
||||||
|
"key": 4,
|
||||||
|
"label": "Routing Slave"
|
||||||
|
},
|
||||||
|
"generic": {
|
||||||
|
"key": 6,
|
||||||
|
"label": "Appliance"
|
||||||
|
},
|
||||||
|
"specific": {
|
||||||
|
"key": 1,
|
||||||
|
"label": "General Appliance"
|
||||||
|
},
|
||||||
|
"mandatorySupportedCCs": [],
|
||||||
|
"mandatoryControlledCCs": []
|
||||||
|
},
|
||||||
|
"commandClasses": [
|
||||||
|
{
|
||||||
|
"id": 134,
|
||||||
|
"name": "Version",
|
||||||
|
"version": 1,
|
||||||
|
"isSecure": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 144,
|
||||||
|
"name": "Energy Production",
|
||||||
|
"version": 1,
|
||||||
|
"isSecure": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "firmwareVersions",
|
||||||
|
"propertyName": "firmwareVersions",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string[]",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave chip firmware versions",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "libraryType",
|
||||||
|
"propertyName": "libraryType",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Library type",
|
||||||
|
"states": {
|
||||||
|
"0": "Unknown",
|
||||||
|
"1": "Static Controller",
|
||||||
|
"2": "Controller",
|
||||||
|
"3": "Enhanced Slave",
|
||||||
|
"4": "Slave",
|
||||||
|
"5": "Installer",
|
||||||
|
"6": "Routing Slave",
|
||||||
|
"7": "Bridge Controller",
|
||||||
|
"8": "Device under Test",
|
||||||
|
"9": "N/A",
|
||||||
|
"10": "AV Remote",
|
||||||
|
"11": "AV Device"
|
||||||
|
},
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "protocolVersion",
|
||||||
|
"propertyName": "protocolVersion",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave protocol version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 144,
|
||||||
|
"commandClassName": "Energy Production",
|
||||||
|
"property": "value",
|
||||||
|
"propertyKey": 0,
|
||||||
|
"propertyName": "value",
|
||||||
|
"propertyKeyName": "0",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Power",
|
||||||
|
"ccSpecific": {
|
||||||
|
"parameter": 0,
|
||||||
|
"scale": 0
|
||||||
|
},
|
||||||
|
"unit": "W",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 1.23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 144,
|
||||||
|
"commandClassName": "Energy Production",
|
||||||
|
"property": "value",
|
||||||
|
"propertyKey": 1,
|
||||||
|
"propertyName": "value",
|
||||||
|
"propertyKeyName": "1",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Production Total",
|
||||||
|
"ccSpecific": {
|
||||||
|
"parameter": 1,
|
||||||
|
"scale": 0
|
||||||
|
},
|
||||||
|
"unit": "Wh",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 1234.56
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 144,
|
||||||
|
"commandClassName": "Energy Production",
|
||||||
|
"property": "value",
|
||||||
|
"propertyKey": 2,
|
||||||
|
"propertyName": "value",
|
||||||
|
"propertyKeyName": "2",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Production Today",
|
||||||
|
"ccSpecific": {
|
||||||
|
"parameter": 2,
|
||||||
|
"scale": 0
|
||||||
|
},
|
||||||
|
"unit": "Wh",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 123.45
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 144,
|
||||||
|
"commandClassName": "Energy Production",
|
||||||
|
"property": "value",
|
||||||
|
"propertyKey": 3,
|
||||||
|
"propertyName": "value",
|
||||||
|
"propertyKeyName": "3",
|
||||||
|
"ccVersion": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Total Time",
|
||||||
|
"ccSpecific": {
|
||||||
|
"parameter": 3,
|
||||||
|
"scale": 0
|
||||||
|
},
|
||||||
|
"unit": "seconds",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 123456
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isFrequentListening": false,
|
||||||
|
"maxDataRate": 100000,
|
||||||
|
"supportedDataRates": [40000, 9600, 100000],
|
||||||
|
"protocolVersion": 3,
|
||||||
|
"supportsBeaming": true,
|
||||||
|
"supportsSecurity": false,
|
||||||
|
"nodeType": 1,
|
||||||
|
"deviceClass": {
|
||||||
|
"basic": {
|
||||||
|
"key": 4,
|
||||||
|
"label": "Routing Slave"
|
||||||
|
},
|
||||||
|
"generic": {
|
||||||
|
"key": 6,
|
||||||
|
"label": "Appliance"
|
||||||
|
},
|
||||||
|
"specific": {
|
||||||
|
"key": 1,
|
||||||
|
"label": "General Appliance"
|
||||||
|
},
|
||||||
|
"mandatorySupportedCCs": [],
|
||||||
|
"mandatoryControlledCCs": []
|
||||||
|
},
|
||||||
|
"interviewStage": "Complete",
|
||||||
|
"statistics": {
|
||||||
|
"commandsTX": 10,
|
||||||
|
"commandsRX": 7,
|
||||||
|
"commandsDroppedRX": 0,
|
||||||
|
"commandsDroppedTX": 0,
|
||||||
|
"timeoutResponse": 1,
|
||||||
|
"rtt": 84.8
|
||||||
|
},
|
||||||
|
"highestSecurityClass": -1,
|
||||||
|
"isControllerNode": false,
|
||||||
|
"keepAwake": false
|
||||||
|
}
|
@ -35,6 +35,7 @@ from homeassistant.const import (
|
|||||||
UnitOfEnergy,
|
UnitOfEnergy,
|
||||||
UnitOfPower,
|
UnitOfPower,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
|
UnitOfTime,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
@ -733,3 +734,54 @@ async def test_statistics_sensors(
|
|||||||
state = hass.states.get(f"{prefix}{suffix_key}")
|
state = hass.states.get(f"{prefix}{suffix_key}")
|
||||||
assert state
|
assert state
|
||||||
assert state.state == str(val)
|
assert state.state == str(val)
|
||||||
|
|
||||||
|
|
||||||
|
ENERGY_PRODUCTION_ENTITY_MAP = {
|
||||||
|
"energy_production_power": {
|
||||||
|
"state": 1.23,
|
||||||
|
"attributes": {
|
||||||
|
"unit_of_measurement": UnitOfPower.WATT,
|
||||||
|
"device_class": SensorDeviceClass.POWER,
|
||||||
|
"state_class": SensorStateClass.MEASUREMENT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"energy_production_total": {
|
||||||
|
"state": 1234.56,
|
||||||
|
"attributes": {
|
||||||
|
"unit_of_measurement": UnitOfEnergy.WATT_HOUR,
|
||||||
|
"device_class": SensorDeviceClass.ENERGY,
|
||||||
|
"state_class": SensorStateClass.TOTAL_INCREASING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"energy_production_today": {
|
||||||
|
"state": 123.45,
|
||||||
|
"attributes": {
|
||||||
|
"unit_of_measurement": UnitOfEnergy.WATT_HOUR,
|
||||||
|
"device_class": SensorDeviceClass.ENERGY,
|
||||||
|
"state_class": SensorStateClass.TOTAL_INCREASING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"energy_production_time": {
|
||||||
|
"state": 123456.0,
|
||||||
|
"attributes": {
|
||||||
|
"unit_of_measurement": UnitOfTime.SECONDS,
|
||||||
|
"device_class": SensorDeviceClass.DURATION,
|
||||||
|
},
|
||||||
|
"missing_attributes": ["state_class"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_energy_production_sensors(
|
||||||
|
hass: HomeAssistant, energy_production, client, integration
|
||||||
|
) -> None:
|
||||||
|
"""Test sensors for Energy Production CC."""
|
||||||
|
for entity_id_suffix, state_data in ENERGY_PRODUCTION_ENTITY_MAP.items():
|
||||||
|
state = hass.states.get(f"sensor.node_2_{entity_id_suffix}")
|
||||||
|
assert state
|
||||||
|
assert state.state == str(state_data["state"])
|
||||||
|
for attr, val in state_data["attributes"].items():
|
||||||
|
assert state.attributes[attr] == val
|
||||||
|
|
||||||
|
for attr in state_data.get("missing_attributes", []):
|
||||||
|
assert attr not in state.attributes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user