Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions homeassistant/components/knx/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@ def is_on(self):
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
"""Return device specific state attributes."""
return {ATTR_COUNTER: self._device.counter}

@property
def force_update(self) -> bool:
"""
Return True if state updates should be forced.

If True, a state change will be triggered anytime the state property is
updated, not just when the value changes.
"""
return self._device.ignore_internal_state
38 changes: 19 additions & 19 deletions homeassistant/components/knx/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import List, Optional

from xknx.devices import Climate as XknxClimate
from xknx.dpt import HVACOperationMode
from xknx.dpt import HVACControllerMode, HVACOperationMode
Comment thread
marvin-w marked this conversation as resolved.

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
Expand All @@ -14,11 +14,11 @@
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS

from .const import DOMAIN, OPERATION_MODES, PRESET_MODES
from .const import CONTROLLER_MODES, DOMAIN, PRESET_MODES
from .knx_entity import KnxEntity

OPERATION_MODES_INV = dict(reversed(item) for item in OPERATION_MODES.items())
PRESET_MODES_INV = dict(reversed(item) for item in PRESET_MODES.items())
CONTROLLER_MODES_INV = {value: key for key, value in CONTROLLER_MODES.items()}
PRESET_MODES_INV = {value: key for key, value in PRESET_MODES.items()}


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
Expand Down Expand Up @@ -92,27 +92,27 @@ def hvac_mode(self) -> Optional[str]:
"""Return current operation ie. heat, cool, idle."""
if self._device.supports_on_off and not self._device.is_on:
return HVAC_MODE_OFF
if self._device.mode.supports_operation_mode:
return OPERATION_MODES.get(
self._device.mode.operation_mode.value, HVAC_MODE_HEAT
if self._device.mode.supports_controller_mode:
return CONTROLLER_MODES.get(
self._device.mode.controller_mode.value, HVAC_MODE_HEAT
)
# default to "heat"
return HVAC_MODE_HEAT

@property
def hvac_modes(self) -> Optional[List[str]]:
"""Return the list of available operation modes."""
_operations = [
OPERATION_MODES.get(operation_mode.value)
for operation_mode in self._device.mode.operation_modes
"""Return the list of available operation/controller modes."""
_controller_modes = [
CONTROLLER_MODES.get(controller_mode.value)
for controller_mode in self._device.mode.controller_modes
]

if self._device.supports_on_off:
if not _operations:
_operations.append(HVAC_MODE_HEAT)
_operations.append(HVAC_MODE_OFF)
if not _controller_modes:
_controller_modes.append(HVAC_MODE_HEAT)
_controller_modes.append(HVAC_MODE_OFF)

_modes = list(set(filter(None, _operations)))
_modes = list(set(filter(None, _controller_modes)))
# default to ["heat"]
return _modes if _modes else [HVAC_MODE_HEAT]

Expand All @@ -123,11 +123,11 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None:
else:
if self._device.supports_on_off and not self._device.is_on:
await self._device.turn_on()
if self._device.mode.supports_operation_mode:
knx_operation_mode = HVACOperationMode(
OPERATION_MODES_INV.get(hvac_mode)
if self._device.mode.supports_controller_mode:
knx_controller_mode = HVACControllerMode(
CONTROLLER_MODES_INV.get(hvac_mode)
)
await self._device.mode.set_operation_mode(knx_operation_mode)
await self._device.mode.set_controller_mode(knx_controller_mode)
self.async_write_ha_state()

@property
Expand Down
8 changes: 6 additions & 2 deletions homeassistant/components/knx/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
PRESET_AWAY,
PRESET_COMFORT,
PRESET_ECO,
PRESET_NONE,
PRESET_SLEEP,
)

DOMAIN = "knx"

CONF_INVERT = "invert"
CONF_STATE_ADDRESS = "state_address"
CONF_SYNC_STATE = "sync_state"
CONF_RESET_AFTER = "reset_after"


class ColorTempModes(Enum):
Expand All @@ -41,8 +44,8 @@ class SupportedPlatforms(Enum):
weather = "weather"


# Map KNX operation modes to HA modes. This list might not be complete.
OPERATION_MODES = {
# Map KNX controller modes to HA modes. This list might not be complete.
CONTROLLER_MODES = {
# Map DPT 20.105 HVAC control modes
"Auto": HVAC_MODE_AUTO,
"Heat": HVAC_MODE_HEAT,
Expand All @@ -54,6 +57,7 @@ class SupportedPlatforms(Enum):

PRESET_MODES = {
# Map DPT 20.102 HVAC operating modes to HA presets
"Auto": PRESET_NONE,
"Frost Protection": PRESET_ECO,
"Night": PRESET_SLEEP,
"Standby": PRESET_AWAY,
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/components/knx/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def _create_climate(knx_module: XKNX, config: ConfigType) -> XknxClimate:
ClimateSchema.CONF_HEAT_COOL_STATE_ADDRESS
),
operation_modes=config.get(ClimateSchema.CONF_OPERATION_MODES),
controller_modes=config.get(ClimateSchema.CONF_CONTROLLER_MODES),
)

return XknxClimate(
Expand Down Expand Up @@ -202,6 +203,7 @@ def _create_switch(knx_module: XKNX, config: ConfigType) -> XknxSwitch:
name=config[CONF_NAME],
group_address=config[CONF_ADDRESS],
group_address_state=config.get(SwitchSchema.CONF_STATE_ADDRESS),
invert=config.get(SwitchSchema.CONF_INVERT),
)


Expand All @@ -212,6 +214,7 @@ def _create_sensor(knx_module: XKNX, config: ConfigType) -> XknxSensor:
name=config[CONF_NAME],
group_address_state=config[SensorSchema.CONF_STATE_ADDRESS],
sync_state=config[SensorSchema.CONF_SYNC_STATE],
always_callback=config[SensorSchema.CONF_ALWAYS_CALLBACK],
Comment thread
marvin-w marked this conversation as resolved.
value_type=config[CONF_TYPE],
)

Expand Down Expand Up @@ -243,10 +246,11 @@ def _create_binary_sensor(knx_module: XKNX, config: ConfigType) -> XknxBinarySen
knx_module,
name=device_name,
group_address_state=config[BinarySensorSchema.CONF_STATE_ADDRESS],
invert=config.get(BinarySensorSchema.CONF_INVERT),
Comment thread
marvin-w marked this conversation as resolved.
sync_state=config[BinarySensorSchema.CONF_SYNC_STATE],
device_class=config.get(CONF_DEVICE_CLASS),
ignore_internal_state=config[BinarySensorSchema.CONF_IGNORE_INTERNAL_STATE],
context_timeout=config[BinarySensorSchema.CONF_CONTEXT_TIMEOUT],
context_timeout=config.get(BinarySensorSchema.CONF_CONTEXT_TIMEOUT),
Comment thread
marvin-w marked this conversation as resolved.
reset_after=config.get(BinarySensorSchema.CONF_RESET_AFTER),
)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/knx/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"domain": "knx",
"name": "KNX",
"documentation": "https://www.home-assistant.io/integrations/knx",
"requirements": ["xknx==0.15.0"],
"requirements": ["xknx==0.15.3"],
Comment thread
marvin-w marked this conversation as resolved.
"codeowners": ["@Julius2342", "@farmio", "@marvin-w"],
"quality_scale": "silver"
}
24 changes: 18 additions & 6 deletions homeassistant/components/knx/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
import homeassistant.helpers.config_validation as cv

from .const import (
CONF_INVERT,
CONF_RESET_AFTER,
CONF_STATE_ADDRESS,
CONF_SYNC_STATE,
OPERATION_MODES,
CONTROLLER_MODES,
PRESET_MODES,
ColorTempModes,
)
Expand Down Expand Up @@ -84,9 +86,10 @@ class BinarySensorSchema:

CONF_STATE_ADDRESS = CONF_STATE_ADDRESS
CONF_SYNC_STATE = CONF_SYNC_STATE
CONF_INVERT = CONF_INVERT
Comment thread
balloob marked this conversation as resolved.
CONF_IGNORE_INTERNAL_STATE = "ignore_internal_state"
CONF_CONTEXT_TIMEOUT = "context_timeout"
CONF_RESET_AFTER = "reset_after"
CONF_RESET_AFTER = CONF_RESET_AFTER
Comment thread
balloob marked this conversation as resolved.

DEFAULT_NAME = "KNX Binary Sensor"

Expand All @@ -101,12 +104,13 @@ class BinarySensorSchema:
cv.boolean,
cv.string,
),
vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=True): cv.boolean,
vol.Optional(CONF_CONTEXT_TIMEOUT, default=1.0): vol.All(
vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=False): cv.boolean,
vol.Required(CONF_STATE_ADDRESS): cv.string,
vol.Optional(CONF_CONTEXT_TIMEOUT): vol.All(
vol.Coerce(float), vol.Range(min=0, max=10)
),
vol.Required(CONF_STATE_ADDRESS): cv.string,
vol.Optional(CONF_DEVICE_CLASS): cv.string,
vol.Optional(CONF_INVERT): cv.boolean,
vol.Optional(CONF_RESET_AFTER): cv.positive_int,
}
),
Expand Down Expand Up @@ -187,6 +191,7 @@ class ClimateSchema:
CONF_OPERATION_MODE_COMFORT_ADDRESS = "operation_mode_comfort_address"
CONF_OPERATION_MODE_STANDBY_ADDRESS = "operation_mode_standby_address"
CONF_OPERATION_MODES = "operation_modes"
CONF_CONTROLLER_MODES = "controller_modes"
CONF_ON_OFF_ADDRESS = "on_off_address"
CONF_ON_OFF_STATE_ADDRESS = "on_off_state_address"
CONF_ON_OFF_INVERT = "on_off_invert"
Expand Down Expand Up @@ -240,7 +245,10 @@ class ClimateSchema:
CONF_ON_OFF_INVERT, default=DEFAULT_ON_OFF_INVERT
): cv.boolean,
vol.Optional(CONF_OPERATION_MODES): vol.All(
cv.ensure_list, [vol.In({**OPERATION_MODES, **PRESET_MODES})]
cv.ensure_list, [vol.In({**PRESET_MODES})]
),
vol.Optional(CONF_CONTROLLER_MODES): vol.All(
cv.ensure_list, [vol.In({**CONTROLLER_MODES})]
),
vol.Optional(CONF_MIN_TEMP): vol.Coerce(float),
vol.Optional(CONF_MAX_TEMP): vol.Coerce(float),
Expand All @@ -252,6 +260,7 @@ class ClimateSchema:
class SwitchSchema:
"""Voluptuous schema for KNX switches."""

CONF_INVERT = CONF_INVERT
CONF_STATE_ADDRESS = CONF_STATE_ADDRESS

DEFAULT_NAME = "KNX Switch"
Expand All @@ -260,6 +269,7 @@ class SwitchSchema:
vol.Required(CONF_ADDRESS): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_STATE_ADDRESS): cv.string,
vol.Optional(CONF_INVERT): cv.boolean,
}
)

Expand Down Expand Up @@ -299,6 +309,7 @@ class NotifySchema:
class SensorSchema:
"""Voluptuous schema for KNX sensors."""

CONF_ALWAYS_CALLBACK = "always_callback"
CONF_STATE_ADDRESS = CONF_STATE_ADDRESS
CONF_SYNC_STATE = CONF_SYNC_STATE
DEFAULT_NAME = "KNX Sensor"
Expand All @@ -311,6 +322,7 @@ class SensorSchema:
cv.boolean,
cv.string,
),
vol.Optional(CONF_ALWAYS_CALLBACK, default=False): cv.boolean,
vol.Required(CONF_STATE_ADDRESS): cv.string,
vol.Required(CONF_TYPE): vol.Any(int, float, str),
}
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/knx/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@ def device_class(self):
if device_class in DEVICE_CLASSES:
return device_class
return None

@property
def force_update(self) -> bool:
"""
Return True if state updates should be forced.

If True, a state change will be triggered anytime the state property is
updated, not just when the value changes.
"""
return self._device.always_callback
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2304,7 +2304,7 @@ xboxapi==2.0.1
xfinity-gateway==0.0.4

# homeassistant.components.knx
xknx==0.15.0
xknx==0.15.3

# homeassistant.components.bluesound
# homeassistant.components.rest
Expand Down