mirror of
https://github.com/esphome/esphome.git
synced 2026-10-09 21:13:12 +00:00
[dlms_meter] Remove deprecated predefined sensor keys (#20386)
This commit is contained in:
@@ -172,43 +172,17 @@ async def to_code(config: ConfigType) -> None:
|
||||
|
||||
hub_id = config[CONF_ID].id
|
||||
|
||||
sensor_count = 0
|
||||
for sens_conf in CORE.config.get(SENSOR_DOMAIN, []):
|
||||
if (
|
||||
sens_conf.get("platform") == DOMAIN
|
||||
and sens_conf.get(CONF_DLMS_METER_ID).id == hub_id
|
||||
):
|
||||
if CONF_OBIS_CODE in sens_conf:
|
||||
sensor_count += 1
|
||||
else:
|
||||
from .sensor import NUMERIC_KEYS
|
||||
|
||||
sensor_count += sum(1 for key in NUMERIC_KEYS if key in sens_conf)
|
||||
|
||||
text_sensor_count = 0
|
||||
for sens_conf in CORE.config.get(TEXT_SENSOR_DOMAIN, []):
|
||||
if (
|
||||
sens_conf.get("platform") == DOMAIN
|
||||
and sens_conf.get(CONF_DLMS_METER_ID).id == hub_id
|
||||
):
|
||||
if CONF_OBIS_CODE in sens_conf:
|
||||
text_sensor_count += 1
|
||||
else:
|
||||
from .text_sensor import TEXT_KEYS
|
||||
|
||||
text_sensor_count += sum(1 for key in TEXT_KEYS if key in sens_conf)
|
||||
|
||||
binary_sensor_count = 0
|
||||
for sens_conf in CORE.config.get(BINARY_SENSOR_DOMAIN, []):
|
||||
if (
|
||||
sens_conf.get("platform") == DOMAIN
|
||||
and sens_conf.get(CONF_DLMS_METER_ID).id == hub_id
|
||||
):
|
||||
binary_sensor_count += 1
|
||||
|
||||
cg.add_define("DLMS_MAX_SENSORS", sensor_count)
|
||||
cg.add_define("DLMS_MAX_TEXT_SENSORS", text_sensor_count)
|
||||
cg.add_define("DLMS_MAX_BINARY_SENSORS", binary_sensor_count)
|
||||
for domain, define in (
|
||||
(SENSOR_DOMAIN, "DLMS_MAX_SENSORS"),
|
||||
(TEXT_SENSOR_DOMAIN, "DLMS_MAX_TEXT_SENSORS"),
|
||||
(BINARY_SENSOR_DOMAIN, "DLMS_MAX_BINARY_SENSORS"),
|
||||
):
|
||||
count = sum(
|
||||
1
|
||||
for conf in CORE.config.get(domain, [])
|
||||
if conf.get("platform") == DOMAIN and conf[CONF_DLMS_METER_ID].id == hub_id
|
||||
)
|
||||
cg.add_define(define, count)
|
||||
|
||||
await cg.register_component(var, config)
|
||||
await uart.register_uart_device(var, config)
|
||||
|
||||
@@ -1,159 +1,59 @@
|
||||
import logging
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
STATE_CLASS_TOTAL_INCREASING,
|
||||
UNIT_AMPERE,
|
||||
UNIT_VOLT,
|
||||
UNIT_WATT,
|
||||
UNIT_WATT_HOURS,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_DLMS_METER_ID, CONF_OBIS_CODE, DlmsMeterComponent, obis_code
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ["dlms_meter"]
|
||||
|
||||
NUMERIC_KEYS = {
|
||||
"voltage_l1": "1.0.32.7.0.255",
|
||||
"voltage_l2": "1.0.52.7.0.255",
|
||||
"voltage_l3": "1.0.72.7.0.255",
|
||||
"current_l1": "1.0.31.7.0.255",
|
||||
"current_l2": "1.0.51.7.0.255",
|
||||
"current_l3": "1.0.71.7.0.255",
|
||||
"active_power_plus": "1.0.1.7.0.255",
|
||||
"active_power_minus": "1.0.2.7.0.255",
|
||||
"active_energy_plus": "1.0.1.8.0.255",
|
||||
"active_energy_minus": "1.0.2.8.0.255",
|
||||
"reactive_energy_plus": "1.0.3.8.0.255",
|
||||
"reactive_energy_minus": "1.0.4.8.0.255",
|
||||
"power_factor": "1.0.13.7.0.255",
|
||||
# Removed in 2026.11.0 - kept to provide helpful error message
|
||||
# Remove before 2027.5.0
|
||||
_MEASUREMENT = "state_class: measurement"
|
||||
_VOLTAGE = f"unit_of_measurement: V, accuracy_decimals: 1, device_class: voltage, {_MEASUREMENT}"
|
||||
_CURRENT = f"unit_of_measurement: A, accuracy_decimals: 2, device_class: current, {_MEASUREMENT}"
|
||||
_POWER = (
|
||||
f"unit_of_measurement: W, accuracy_decimals: 0, device_class: power, {_MEASUREMENT}"
|
||||
)
|
||||
_ENERGY = (
|
||||
"unit_of_measurement: Wh, accuracy_decimals: 0, device_class: energy, "
|
||||
"state_class: total_increasing"
|
||||
)
|
||||
_POWER_FACTOR = f"accuracy_decimals: 3, device_class: power_factor, {_MEASUREMENT}"
|
||||
REMOVED_KEYS = {
|
||||
"voltage_l1": ("1.0.32.7.0.255", _VOLTAGE),
|
||||
"voltage_l2": ("1.0.52.7.0.255", _VOLTAGE),
|
||||
"voltage_l3": ("1.0.72.7.0.255", _VOLTAGE),
|
||||
"current_l1": ("1.0.31.7.0.255", _CURRENT),
|
||||
"current_l2": ("1.0.51.7.0.255", _CURRENT),
|
||||
"current_l3": ("1.0.71.7.0.255", _CURRENT),
|
||||
"active_power_plus": ("1.0.1.7.0.255", _POWER),
|
||||
"active_power_minus": ("1.0.2.7.0.255", _POWER),
|
||||
"active_energy_plus": ("1.0.1.8.0.255", _ENERGY),
|
||||
"active_energy_minus": ("1.0.2.8.0.255", _ENERGY),
|
||||
"reactive_energy_plus": ("1.0.3.8.0.255", _ENERGY),
|
||||
"reactive_energy_minus": ("1.0.4.8.0.255", _ENERGY),
|
||||
"power_factor": ("1.0.13.7.0.255", _POWER_FACTOR),
|
||||
}
|
||||
|
||||
DYNAMIC_SCHEMA = sensor.sensor_schema().extend(
|
||||
|
||||
CONFIG_SCHEMA = sensor.sensor_schema().extend(
|
||||
{
|
||||
cv.GenerateID(CONF_DLMS_METER_ID): cv.use_id(DlmsMeterComponent),
|
||||
cv.Required(CONF_OBIS_CODE): obis_code,
|
||||
**{
|
||||
cv.Optional(key): cv.invalid(
|
||||
f"The predefined '{key}' key was removed in ESPHome 2026.11.0. "
|
||||
f"Add a separate '- platform: dlms_meter' sensor with "
|
||||
f'obis_code: "{obis}" and {settings}'
|
||||
)
|
||||
for key, (obis, settings) in REMOVED_KEYS.items()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def deprecation_warning(config: ConfigType) -> ConfigType:
|
||||
_LOGGER.warning(
|
||||
"The dlms_meter sensor schema using predefined keys (e.g., 'voltage_l1') is deprecated and will be removed in 2026.11.0. "
|
||||
"Please update your configuration to use the new schema with 'obis_code'."
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
OLD_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_DLMS_METER_ID): cv.use_id(DlmsMeterComponent),
|
||||
cv.Optional("voltage_l1"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("voltage_l2"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("voltage_l3"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("current_l1"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_AMPERE,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("current_l2"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_AMPERE,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("current_l3"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_AMPERE,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("active_power_plus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("active_power_minus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional("active_energy_plus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT_HOURS,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
cv.Optional("active_energy_minus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT_HOURS,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
cv.Optional("reactive_energy_plus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT_HOURS,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
cv.Optional("reactive_energy_minus"): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT_HOURS,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
cv.Optional("power_factor"): sensor.sensor_schema(
|
||||
accuracy_decimals=3,
|
||||
device_class=DEVICE_CLASS_POWER_FACTOR,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
deprecation_warning,
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Any(DYNAMIC_SCHEMA, OLD_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_DLMS_METER_ID])
|
||||
|
||||
if obis := config.get(CONF_OBIS_CODE):
|
||||
var = await sensor.new_sensor(config)
|
||||
cg.add(hub.register_sensor(obis, var))
|
||||
else:
|
||||
for key, obis_val in NUMERIC_KEYS.items():
|
||||
if sensor_config := config.get(key):
|
||||
sens = await sensor.new_sensor(sensor_config)
|
||||
cg.add(hub.register_sensor(obis_val, sens))
|
||||
var = await sensor.new_sensor(config)
|
||||
cg.add(hub.register_sensor(config[CONF_OBIS_CODE], var))
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import logging
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
@@ -7,54 +5,33 @@ from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_DLMS_METER_ID, CONF_OBIS_CODE, DlmsMeterComponent, obis_code
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ["dlms_meter"]
|
||||
|
||||
TEXT_KEYS = {
|
||||
# Removed in 2026.11.0 - kept to provide helpful error message
|
||||
# Remove before 2027.5.0
|
||||
REMOVED_KEYS = {
|
||||
"timestamp": "0.0.1.0.0.255",
|
||||
"meternumber": "0.0.96.1.0.255",
|
||||
}
|
||||
|
||||
DYNAMIC_SCHEMA = text_sensor.text_sensor_schema().extend(
|
||||
|
||||
CONFIG_SCHEMA = text_sensor.text_sensor_schema().extend(
|
||||
{
|
||||
cv.GenerateID(CONF_DLMS_METER_ID): cv.use_id(DlmsMeterComponent),
|
||||
cv.Required(CONF_OBIS_CODE): obis_code,
|
||||
**{
|
||||
cv.Optional(key): cv.invalid(
|
||||
f"The predefined '{key}' key was removed in ESPHome 2026.11.0. "
|
||||
f"Add a separate '- platform: dlms_meter' text sensor with "
|
||||
f'obis_code: "{obis}" instead'
|
||||
)
|
||||
for key, obis in REMOVED_KEYS.items()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def deprecation_warning(config: ConfigType) -> ConfigType:
|
||||
_LOGGER.warning(
|
||||
"The dlms_meter text_sensor schema using predefined keys (e.g., 'timestamp') is deprecated and will be removed in 2026.11.0. "
|
||||
"Please update your configuration to use the new schema with 'obis_code'."
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
OLD_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_DLMS_METER_ID): cv.use_id(DlmsMeterComponent),
|
||||
cv.Optional("timestamp"): text_sensor.text_sensor_schema(),
|
||||
cv.Optional("meternumber"): text_sensor.text_sensor_schema(),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
deprecation_warning,
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Any(DYNAMIC_SCHEMA, OLD_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_DLMS_METER_ID])
|
||||
|
||||
if obis := config.get(CONF_OBIS_CODE):
|
||||
var = await text_sensor.new_text_sensor(config)
|
||||
cg.add(hub.register_text_sensor(obis, var))
|
||||
else:
|
||||
for key, obis_val in TEXT_KEYS.items():
|
||||
if text_sensor_config := config.get(key):
|
||||
sens = await text_sensor.new_text_sensor(text_sensor_config)
|
||||
cg.add(hub.register_text_sensor(obis_val, sens))
|
||||
var = await text_sensor.new_text_sensor(config)
|
||||
cg.add(hub.register_text_sensor(config[CONF_OBIS_CODE], var))
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Tests for the dlms_meter predefined keys removed in 2026.11.0."""
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
import pytest
|
||||
from voluptuous import Invalid, MultipleInvalid
|
||||
|
||||
from esphome.components.dlms_meter.sensor import CONFIG_SCHEMA as SENSOR_SCHEMA
|
||||
from esphome.components.dlms_meter.text_sensor import (
|
||||
CONFIG_SCHEMA as TEXT_SENSOR_SCHEMA,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
|
||||
def _errors(schema: Callable[[ConfigType], ConfigType], config: ConfigType) -> str:
|
||||
with pytest.raises(Invalid) as exc_info:
|
||||
schema(config)
|
||||
errors = (
|
||||
exc_info.value.errors
|
||||
if isinstance(exc_info.value, MultipleInvalid)
|
||||
else [exc_info.value]
|
||||
)
|
||||
return "\n".join(str(error) for error in errors)
|
||||
|
||||
|
||||
def test_removed_sensor_key_names_its_replacement() -> None:
|
||||
errors = _errors(SENSOR_SCHEMA, {"voltage_l1": {"name": "Voltage"}})
|
||||
assert 'obis_code: "1.0.32.7.0.255" and unit_of_measurement: V' in errors
|
||||
|
||||
|
||||
def test_removed_text_sensor_key_names_its_replacement() -> None:
|
||||
errors = _errors(TEXT_SENSOR_SCHEMA, {"timestamp": {"name": "Timestamp"}})
|
||||
assert 'obis_code: "0.0.1.0.0.255"' in errors
|
||||
@@ -15,57 +15,36 @@ dlms_meter:
|
||||
default_obis: "0.0.1.0.0.255"
|
||||
|
||||
sensor:
|
||||
# Old Schema tests
|
||||
- platform: dlms_meter
|
||||
voltage_l1:
|
||||
name: "Voltage L1"
|
||||
voltage_l2:
|
||||
name: "Voltage L2"
|
||||
voltage_l3:
|
||||
name: "Voltage L3"
|
||||
current_l1:
|
||||
name: "Current L1"
|
||||
current_l2:
|
||||
name: "Current L2"
|
||||
current_l3:
|
||||
name: "Current L3"
|
||||
active_power_plus:
|
||||
name: "Active power taken from grid"
|
||||
active_power_minus:
|
||||
name: "Active power put into grid"
|
||||
active_energy_plus:
|
||||
name: "Active energy taken from grid"
|
||||
active_energy_minus:
|
||||
name: "Active energy put into grid"
|
||||
reactive_energy_plus:
|
||||
name: "Reactive energy taken from grid"
|
||||
reactive_energy_minus:
|
||||
name: "Reactive energy put into grid"
|
||||
power_factor:
|
||||
name: "Power factor"
|
||||
obis_code: "1.0.32.7.0.255"
|
||||
name: "Voltage L1"
|
||||
unit_of_measurement: V
|
||||
accuracy_decimals: 1
|
||||
device_class: voltage
|
||||
state_class: measurement
|
||||
- platform: dlms_meter
|
||||
obis_code: "1.0.1.8.0.255"
|
||||
name: "Active energy taken from grid"
|
||||
unit_of_measurement: Wh
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
|
||||
# Dynamic Schema tests
|
||||
- platform: dlms_meter
|
||||
dlms_meter_id: dlms_meter_hub
|
||||
obis_code: "1-0:99.99.9"
|
||||
name: "Custom Dynamic Sensor"
|
||||
|
||||
text_sensor:
|
||||
# Old Schema tests
|
||||
- platform: dlms_meter
|
||||
timestamp:
|
||||
name: "timestamp"
|
||||
meternumber:
|
||||
name: "Meter Number"
|
||||
obis_code: "0.0.1.0.0.255"
|
||||
name: "timestamp"
|
||||
|
||||
# Dynamic Schema tests
|
||||
- platform: dlms_meter
|
||||
dlms_meter_id: dlms_meter_hub
|
||||
obis_code: "0-0:99.99.9"
|
||||
name: "Custom Dynamic Text Sensor"
|
||||
|
||||
binary_sensor:
|
||||
# Dynamic Schema tests (Binary sensors only use the dynamic schema)
|
||||
- platform: dlms_meter
|
||||
dlms_meter_id: dlms_meter_hub
|
||||
obis_code: "0-1:2.3.4"
|
||||
|
||||
Reference in New Issue
Block a user