1 """Exposures to KNX bus."""
3 from __future__
import annotations
5 from collections.abc
import Callable
9 from xknx.devices
import DateDevice, DateTimeDevice, ExposeSensor, TimeDevice
10 from xknx.dpt
import DPTNumeric, DPTString
11 from xknx.exceptions
import ConversionError
12 from xknx.remote_value
import RemoteValueSensor
24 EventStateChangedData,
34 from .const
import CONF_RESPOND_TO_READ, KNX_ADDRESS
35 from .schema
import ExposeSchema
37 _LOGGER = logging.getLogger(__name__)
42 hass: HomeAssistant, xknx: XKNX, config: ConfigType
43 ) -> KNXExposeSensor | KNXExposeTime:
44 """Create exposures from config."""
46 expose_type = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE]
48 exposure: KNXExposeSensor | KNXExposeTime
50 isinstance(expose_type, str)
51 and expose_type.lower()
in ExposeSchema.EXPOSE_TIME_TYPES
63 exposure.async_register()
68 """Object to Expose Home Assistant entity to KNX bus."""
76 """Initialize of Expose class."""
80 self.entity_id: str = config[CONF_ENTITY_ID]
81 self.expose_attribute: str |
None = config.get(
82 ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE
84 self.
expose_defaultexpose_default = config.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT)
85 self.
expose_typeexpose_type: int | str = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE]
86 self.value_template: Template |
None = config.get(CONF_VALUE_TEMPLATE)
89 self.device: ExposeSensor = ExposeSensor(
91 name=f
"{self.entity_id}__{self.expose_attribute or "state
"}",
92 group_address=config[KNX_ADDRESS],
93 respond_to_read=config[CONF_RESPOND_TO_READ],
95 cooldown=config[ExposeSchema.CONF_KNX_EXPOSE_COOLDOWN],
100 """Register listener."""
104 self.
xknxxknx.devices.async_add(self.device)
109 """Initialize state of the exposure."""
110 init_state = self.
hasshass.states.get(self.entity_id)
113 self.device.sensor_value.value = state_value
114 except ConversionError:
115 _LOGGER.exception(
"Error during sending of expose sensor value")
119 """Prepare for deletion."""
123 self.
xknxxknx.devices.async_remove(self.device)
126 """Extract value from state."""
127 if state
is None or state.state
in (STATE_UNKNOWN, STATE_UNAVAILABLE):
131 elif self.expose_attribute
is not None:
132 _attr = state.attributes.get(self.expose_attribute)
133 value = _attr
if _attr
is not None else self.
expose_defaultexpose_default
137 if self.value_template
is not None:
139 value = self.value_template.async_render_with_possible_json_value(
140 value, error_value=
None
142 except (TemplateError, TypeError, ValueError)
as err:
144 "Error rendering value template for KNX expose %s %s: %s",
146 self.value_template.template,
152 if value
in (1, STATE_ON,
"True"):
154 if value
in (0, STATE_OFF,
"False"):
156 if value
is not None and (
157 isinstance(self.device.sensor_value, RemoteValueSensor)
160 if issubclass(self.device.sensor_value.dpt_class, DPTNumeric):
162 if issubclass(self.device.sensor_value.dpt_class, DPTString):
164 return str(value)[:14]
165 except (ValueError, TypeError)
as err:
167 'Could not expose %s %s value "%s" to KNX: Conversion failed: %s',
169 self.expose_attribute
or "state",
177 """Handle entity change."""
178 new_state = event.data[
"new_state"]
181 old_state = event.data[
"old_state"]
183 old_value = self.
_get_expose_value_get_expose_value(old_state)
if old_state
is not None else None
185 if new_value != old_value:
189 """Set new value on xknx ExposeSensor."""
191 await self.device.set(value)
192 except ConversionError
as err:
194 'Could not expose %s %s value "%s" to KNX: %s',
196 self.expose_attribute
or "state",
203 """Object to Expose Time/Date object to KNX bus."""
205 def __init__(self, xknx: XKNX, config: ConfigType) ->
None:
206 """Initialize of Expose class."""
208 expose_type = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE]
209 xknx_device_cls: type[DateDevice | DateTimeDevice | TimeDevice]
211 case ExposeSchema.CONF_DATE:
212 xknx_device_cls = DateDevice
213 case ExposeSchema.CONF_DATETIME:
214 xknx_device_cls = DateTimeDevice
215 case ExposeSchema.CONF_TIME:
216 xknx_device_cls = TimeDevice
219 name=expose_type.capitalize(),
221 group_address=config[KNX_ADDRESS],
226 """Register listener."""
227 self.
xknxxknx.devices.async_add(self.
devicedevice)
231 """Prepare for deletion."""
232 self.
xknxxknx.devices.async_remove(self.
devicedevice)
None async_register(self)
bool|int|float|str|None _get_expose_value(self, State|None state)
None _init_expose_state(self)
None _async_entity_changed(self, Event[EventStateChangedData] event)
None __init__(self, HomeAssistant hass, XKNX xknx, ConfigType config)
None _async_set_knx_value(self, StateType value)
None __init__(self, XKNX xknx, ConfigType config)
None async_register(self)
KNXExposeSensor|KNXExposeTime create_knx_exposure(HomeAssistant hass, XKNX xknx, ConfigType config)
CALLBACK_TYPE async_track_state_change_event(HomeAssistant hass, str|Iterable[str] entity_ids, Callable[[Event[EventStateChangedData]], Any] action, HassJobType|None job_type=None)