-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(knx): enable sensor creation via API #133979
base: dev
Are you sure you want to change the base?
Conversation
Hey there @Julius2342, @farmio, @marvin-w, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
self._attr_device_info = DeviceInfo(identifiers={(DOMAIN, device_info)}) | ||
|
||
# If no entity description is defined, fall back to the entity_config dictionary | ||
if entity_config and not getattr(self, "entity_description", None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if entity_config and not getattr(self, "entity_description", None): | |
if entity_config and not hasattr(self, "entity_description"): |
When we start using EntityDescription, I think in a separate PR, we should just move all existing UI configs to EntityDescription and remove this check as well as the last 2 positional arguments of __init__()
instead of using 2 different ways of configuration.
from .const import ATTR_SOURCE, DOMAIN, KNX_MODULE_KEY | ||
from .entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity | ||
from .light import CONF_GA_STATE, CONF_SYNC_STATE | ||
from .schema import SensorSchema | ||
from .storage.const import CONF_ALWAYS_CALLBACK, CONF_DEVICE_INFO, CONF_ENTITY | ||
from .storage.entity_store_schema import CONF_GA_SENSOR, CONF_VALUE_TYPE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from .const import ATTR_SOURCE, DOMAIN, KNX_MODULE_KEY | |
from .entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity | |
from .light import CONF_GA_STATE, CONF_SYNC_STATE | |
from .schema import SensorSchema | |
from .storage.const import CONF_ALWAYS_CALLBACK, CONF_DEVICE_INFO, CONF_ENTITY | |
from .storage.entity_store_schema import CONF_GA_SENSOR, CONF_VALUE_TYPE | |
from .const import ATTR_SOURCE, CONF_SYNC_STATE, DOMAIN, KNX_MODULE_KEY | |
from .entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity | |
from .schema import SensorSchema | |
from .storage.const import ( | |
CONF_ALWAYS_CALLBACK, | |
CONF_DEVICE_INFO, | |
CONF_ENTITY, | |
CONF_GA_SENSOR, | |
CONF_GA_STATE, | |
CONF_VALUE_TYPE, | |
) |
@@ -49,10 +55,10 @@ class KNXSystemEntityDescription(SensorEntityDescription): | |||
entity_category: EntityCategory = EntityCategory.DIAGNOSTIC | |||
has_entity_name: bool = True | |||
should_poll: bool = True | |||
value_fn: Callable[[KNXModule], StateType | datetime] = lambda knx: None | |||
value_fn: Callable[[KNXModule], StateType | datetime | None] = lambda knx: None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value_fn: Callable[[KNXModule], StateType | datetime | None] = lambda knx: None | |
value_fn: Callable[[KNXModule], StateType | datetime] = lambda knx: None |
StateType already includes None
|
||
self._attr_device_info = knx.interface_device.device_info | ||
self._attr_should_poll = description.should_poll | ||
self._attr_translation_key = description.key | ||
self._attr_unique_id = f"_{knx.entry.entry_id}_{description.key}" | ||
|
||
@property | ||
def native_value(self) -> StateType | datetime: | ||
def native_value(self) -> StateType | datetime | None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def native_value(self) -> StateType | datetime | None: | |
def native_value(self) -> StateType | datetime: |
StateType already includes None
|
||
@dataclass(frozen=True, kw_only=True) | ||
class KnxSensorDescription(SensorEntityDescription): | ||
"""Class describing KNX system sensor entities.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"""Class describing KNX system sensor entities.""" | |
"""Class describing KNX sensor entities.""" |
_state_class: SensorStateClass | None = ( | ||
SensorStateClass(state_class) if state_class else None | ||
) | ||
|
||
_entity_category: EntityCategory | None = ( | ||
EntityCategory(entity_category) if entity_category else None | ||
) | ||
|
||
_device_class: SensorDeviceClass | None = ( | ||
SensorDeviceClass(device_class) if device_class else None | ||
) | ||
|
||
if not _device_class: | ||
_device_class = try_parse_enum(SensorDeviceClass, device.ha_device_class()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
YAML config is already coerced to those StrEnum
members by voluptuous. UI aren't. I'd move these to the ui-specific branch and have arguments state_class: SensorStateClass | None
instead of state_class: str | None
here.
_device_info: DeviceInfo | None = ( | ||
DeviceInfo(identifiers={(DOMAIN, device_info)}) if device_info else None | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
YAML doesn't support devices, so move to UI-specific branch and set default in arguments here device_info: DeviceInfo | None = None
CONF_STATE_CLASS: Final = "state_class" | ||
CONF_DEVICE_CLASS: Final = "device_class" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state_class
can be imported from homeassistant.components.sensor.const
and device_class
from homeassistant.const
vol.Optional(CONF_STATE_CLASS, default=None): vol.Maybe(str), | ||
vol.Optional(CONF_DEVICE_CLASS, default=None): vol.Maybe(str), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state_class
and device_class
are sensor platform specific - so should not be added to BASE_ENTITY_SCHEMA
and should be validated by their respective schema instead of str
.
vol.Required(CONF_GA_SENSOR): GASelector(state_required=True), | ||
vol.Required(CONF_VALUE_TYPE): str, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vol.Required(CONF_GA_SENSOR): GASelector(state_required=True), | |
vol.Required(CONF_VALUE_TYPE): str, | |
vol.Required(CONF_GA_SENSOR): GASelector( | |
write=False, | |
state_required=True, | |
dpt=[], | |
), |
The interesting thing for UI configurable sensor entities will be how to pass and validate available dpt
from xknx.dpt
up to the UI and back.
value_type
can be omitted then.
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
device_info: DeviceInfo | None = None | ||
|
||
|
||
class KnxSensorDescriptionFactory: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this only holds @staticmethod
, it can be either omitted and moved to plain module functions, or if you prefer, moved to methods or classmethods of KnxSensorDescription
Hi 👋!
Just a small remark: I don't think it is necessary to keep YAML and UI entity behaviour 100% consistent. If there are features for UI entities that aren't possible or allowed for YAML then that is fine for me (eg. HA devices).
Would it make sense to build both, the backend and frontend, before merging into HA Core? |
Breaking change
NONE
Proposed change
This PR introduces the necessary backend changes to allow KNX sensors to be created and managed via the websocket API/frontend. While no UI changes are contributed yet, this only lays the technical foundation.
In addition, I’d like to suggest using EntityDescription objects as a general approach moving forward. This allows us to separate the entity logic from the configuration mapping (how it’s set up via YAML or the UI). By keeping these concerns apart, we make the code easier to maintain, reduce duplication, and ensure consistent behavior across different configuration methods.
Type of change
Additional information
I’d be happy to implement the necessary UI changes as well. However, due to time constraints, it will likely take around two weeks before I can start working on them.
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
.To help with the load of incoming pull requests: