Files
esphome-lsm6ds/esphome/components/emontx/sensor/__init__.py
T
14bcdfe700 [emontx] emonTx component (#9027)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-04-07 22:29:55 +00:00

134 lines
3.9 KiB
Python

import esphome.codegen as cg
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_ACCURACY_DECIMALS,
CONF_DEVICE_CLASS,
CONF_ID,
CONF_STATE_CLASS,
CONF_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_POWER_FACTOR,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_EMPTY,
UNIT_PULSES,
UNIT_VOLT,
UNIT_WATT,
UNIT_WATT_HOURS,
)
from esphome.types import ConfigType
from .. import CONF_EMONTX_ID, CONF_TAG_NAME, EmonTx, emontx_ns
EmonTxSensor = emontx_ns.class_("EmonTxSensor", sensor.Sensor, cg.Component)
# Define sensor type configurations by prefix
SENSOR_CONFIGS = {
"P": {
CONF_UNIT_OF_MEASUREMENT: UNIT_WATT,
CONF_DEVICE_CLASS: DEVICE_CLASS_POWER,
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 0,
},
"E": {
CONF_UNIT_OF_MEASUREMENT: UNIT_WATT_HOURS,
CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY,
CONF_STATE_CLASS: STATE_CLASS_TOTAL_INCREASING,
CONF_ACCURACY_DECIMALS: 0,
},
"V": {
CONF_UNIT_OF_MEASUREMENT: UNIT_VOLT,
CONF_DEVICE_CLASS: DEVICE_CLASS_VOLTAGE,
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 2,
},
"I": {
CONF_UNIT_OF_MEASUREMENT: UNIT_AMPERE,
CONF_DEVICE_CLASS: DEVICE_CLASS_CURRENT,
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 2,
},
"T": {
CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS,
CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 2,
},
}
# Pattern-based configurations
PATTERN_CONFIGS = {
"PULSE": {
CONF_UNIT_OF_MEASUREMENT: UNIT_PULSES,
CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY,
CONF_ACCURACY_DECIMALS: 0,
},
"PF": {
CONF_UNIT_OF_MEASUREMENT: UNIT_EMPTY,
CONF_DEVICE_CLASS: DEVICE_CLASS_POWER_FACTOR,
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 2,
},
}
# Create a base schema that's flexible for any tag
BASE_SCHEMA = sensor.sensor_schema(
EmonTxSensor,
state_class=STATE_CLASS_MEASUREMENT,
accuracy_decimals=0,
).extend(
{
cv.GenerateID(CONF_EMONTX_ID): cv.use_id(EmonTx),
cv.Required(CONF_TAG_NAME): cv.string,
}
)
def apply_tag_defaults(config: ConfigType) -> ConfigType:
"""Apply defaults based on tag prefix if applicable, but don't restrict any tags."""
tag = config[CONF_TAG_NAME]
# Skip if tag is too short
if len(tag) < 2:
return config
# Check if this tag starts with a known prefix
tag_upper = tag.upper()
for pattern, pattern_config in PATTERN_CONFIGS.items():
if tag_upper.startswith(pattern):
# Apply pattern defaults if not overridden by user
for key, value in pattern_config.items():
if key not in config:
config[key] = value
return config
# Only apply defaults for known prefixes with numeric indices
prefix = tag_upper[0]
if prefix in SENSOR_CONFIGS and len(tag) > 1 and tag[1:].isdigit():
# Apply defaults for known tag types, but only if not overridden by user
defaults = SENSOR_CONFIGS[prefix]
for key, value in defaults.items():
if key not in config:
config[key] = value
return config
CONFIG_SCHEMA = cv.All(BASE_SCHEMA, apply_tag_defaults)
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await sensor.register_sensor(var, config)
hub = await cg.get_variable(config[CONF_EMONTX_ID])
cg.add(hub.register_sensor(config[CONF_TAG_NAME], var))