Update xknx to 0.14.2 (#40304)

* Updates xknx to 0.14.0

* Review: Explicity add state attributes to weather device

* Review: Remove state attributes from weather device

* Review: Add `counter` as a state attribute to binary_sensors
This commit is contained in:
Marvin Wichmann 2020-09-20 23:40:36 +02:00 committed by GitHub
parent 0c077685b6
commit 45288431f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 63 deletions

View file

@ -6,7 +6,12 @@ from xknx import XKNX
from xknx.devices import DateTime, ExposeSensor
from xknx.dpt import DPTArray, DPTBase, DPTBinary
from xknx.exceptions import XKNXException
from xknx.io import DEFAULT_MCAST_PORT, ConnectionConfig, ConnectionType
from xknx.io import (
DEFAULT_MCAST_GRP,
DEFAULT_MCAST_PORT,
ConnectionConfig,
ConnectionType,
)
from xknx.telegram import AddressFilter, GroupAddress, Telegram
from homeassistant.const import (
@ -48,6 +53,9 @@ CONF_KNX_ROUTING = "routing"
CONF_KNX_TUNNELING = "tunneling"
CONF_KNX_FIRE_EVENT = "fire_event"
CONF_KNX_FIRE_EVENT_FILTER = "fire_event_filter"
CONF_KNX_INDIVIDUAL_ADDRESS = "individual_address"
CONF_KNX_MCAST_GRP = "multicast_group"
CONF_KNX_MCAST_PORT = "multicast_port"
CONF_KNX_STATE_UPDATER = "state_updater"
CONF_KNX_RATE_LIMIT = "rate_limit"
CONF_KNX_EXPOSE = "expose"
@ -72,6 +80,11 @@ CONFIG_SCHEMA = vol.Schema(
vol.Inclusive(CONF_KNX_FIRE_EVENT_FILTER, "fire_ev"): vol.All(
cv.ensure_list, [cv.string]
),
vol.Optional(
CONF_KNX_INDIVIDUAL_ADDRESS, default=XKNX.DEFAULT_ADDRESS
): cv.string,
vol.Optional(CONF_KNX_MCAST_GRP, default=DEFAULT_MCAST_GRP): cv.string,
vol.Optional(CONF_KNX_MCAST_PORT, default=DEFAULT_MCAST_PORT): cv.port,
vol.Optional(CONF_KNX_STATE_UPDATER, default=True): cv.boolean,
vol.Optional(CONF_KNX_RATE_LIMIT, default=20): vol.All(
vol.Coerce(int), vol.Range(min=1, max=100)
@ -130,17 +143,15 @@ async def async_setup(hass, config):
hass.data[DATA_KNX].async_create_exposures()
await hass.data[DATA_KNX].start()
except XKNXException as ex:
_LOGGER.warning("Can't connect to KNX interface: %s", ex)
_LOGGER.warning("Could not connect to KNX interface: %s", ex)
hass.components.persistent_notification.async_create(
f"Can't connect to KNX interface: <br><b>{ex}</b>", title="KNX"
f"Could not connect to KNX interface: <br><b>{ex}</b>", title="KNX"
)
for platform in SupportedPlatforms:
if platform.value in config[DOMAIN]:
for device_config in config[DOMAIN][platform.value]:
create_knx_device(
hass, platform, hass.data[DATA_KNX].xknx, device_config
)
create_knx_device(platform, hass.data[DATA_KNX].xknx, device_config)
# We need to wait until all entities are loaded into the device list since they could also be created from other platforms
for platform in SupportedPlatforms:
@ -181,7 +192,10 @@ class KNXModule:
self.xknx = XKNX(
config=self.config_file(),
loop=self.hass.loop,
own_address=self.config[DOMAIN][CONF_KNX_INDIVIDUAL_ADDRESS],
rate_limit=self.config[DOMAIN][CONF_KNX_RATE_LIMIT],
multicast_group=self.config[DOMAIN][CONF_KNX_MCAST_GRP],
multicast_port=self.config[DOMAIN][CONF_KNX_MCAST_PORT],
)
async def start(self):
@ -229,12 +243,10 @@ class KNXModule:
def connection_config_tunneling(self):
"""Return the connection_config if tunneling is configured."""
gateway_ip = self.config[DOMAIN][CONF_KNX_TUNNELING][CONF_HOST]
gateway_port = self.config[DOMAIN][CONF_KNX_TUNNELING].get(CONF_PORT)
gateway_port = self.config[DOMAIN][CONF_KNX_TUNNELING][CONF_PORT]
local_ip = self.config[DOMAIN][CONF_KNX_TUNNELING].get(
ConnectionSchema.CONF_KNX_LOCAL_IP
)
if gateway_port is None:
gateway_port = DEFAULT_MCAST_PORT
return ConnectionConfig(
connection_type=ConnectionType.TUNNELING,
gateway_ip=gateway_ip,
@ -267,7 +279,7 @@ class KNXModule:
attribute = to_expose.get(ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE)
default = to_expose.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT)
address = to_expose.get(ExposeSchema.CONF_KNX_EXPOSE_ADDRESS)
if expose_type in ["time", "date", "datetime"]:
if expose_type.lower() in ["time", "date", "datetime"]:
exposure = KNXExposeTime(self.xknx, expose_type, address)
exposure.async_register()
self.exposures.append(exposure)
@ -313,29 +325,29 @@ class KNXModule:
payload = calculate_payload(attr_payload)
address = GroupAddress(attr_address)
telegram = Telegram()
telegram.payload = payload
telegram.group_address = address
telegram = Telegram(group_address=address, payload=payload)
await self.xknx.telegrams.put(telegram)
class KNXExposeTime:
"""Object to Expose Time/Date object to KNX bus."""
def __init__(self, xknx, expose_type, address):
def __init__(self, xknx: XKNX, expose_type: str, address: str):
"""Initialize of Expose class."""
self.xknx = xknx
self.type = expose_type
self.expose_type = expose_type
self.address = address
self.device = None
@callback
def async_register(self):
"""Register listener."""
broadcast_type_string = self.type.upper()
broadcast_type = broadcast_type_string
self.device = DateTime(
self.xknx, "Time", broadcast_type=broadcast_type, group_address=self.address
self.xknx,
name=self.expose_type.capitalize(),
broadcast_type=self.expose_type.upper(),
localtime=True,
group_address=self.address,
)

View file

@ -1,10 +1,12 @@
"""Support for KNX/IP binary sensors."""
from typing import Any, Dict, Optional
from xknx.devices import BinarySensor as XknxBinarySensor
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.core import callback
from . import DATA_KNX
from .const import ATTR_COUNTER, DATA_KNX
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
@ -27,7 +29,7 @@ class KNXBinarySensor(BinarySensorEntity):
def async_register_callbacks(self):
"""Register callbacks to update hass after device was changed."""
async def after_update_callback(device):
async def after_update_callback(device: XknxBinarySensor):
"""Call after device was updated."""
self.async_write_ha_state()
@ -65,3 +67,8 @@ class KNXBinarySensor(BinarySensorEntity):
def is_on(self):
"""Return true if the binary sensor is on."""
return self.device.is_on()
@property
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
"""Return device specific state attributes."""
return {ATTR_COUNTER: self.device.counter}

View file

@ -60,3 +60,5 @@ PRESET_MODES = {
"Standby": PRESET_AWAY,
"Comfort": PRESET_COMFORT,
}
ATTR_COUNTER = "counter"

View file

@ -1,7 +1,6 @@
"""Factory function to initialize KNX devices from config."""
from xknx import XKNX
from xknx.devices import (
ActionCallback as XknxActionCallback,
BinarySensor as XknxBinarySensor,
Climate as XknxClimate,
ClimateMode as XknxClimateMode,
@ -16,11 +15,9 @@ from xknx.devices import (
)
from homeassistant.const import CONF_ADDRESS, CONF_DEVICE_CLASS, CONF_NAME, CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.script import Script
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN, ColorTempModes, SupportedPlatforms
from .const import ColorTempModes, SupportedPlatforms
from .schema import (
BinarySensorSchema,
ClimateSchema,
@ -34,7 +31,6 @@ from .schema import (
def create_knx_device(
hass: HomeAssistant,
platform: SupportedPlatforms,
knx_module: XKNX,
config: ConfigType,
@ -62,7 +58,7 @@ def create_knx_device(
return _create_scene(knx_module, config)
if platform is SupportedPlatforms.binary_sensor:
return _create_binary_sensor(hass, knx_module, config)
return _create_binary_sensor(knx_module, config)
if platform is SupportedPlatforms.weather:
return _create_weather(knx_module, config)
@ -239,24 +235,9 @@ def _create_scene(knx_module: XKNX, config: ConfigType) -> XknxScene:
)
def _create_binary_sensor(
hass: HomeAssistant, knx_module: XKNX, config: ConfigType
) -> XknxBinarySensor:
def _create_binary_sensor(knx_module: XKNX, config: ConfigType) -> XknxBinarySensor:
"""Return a KNX binary sensor to be used within XKNX."""
device_name = config[CONF_NAME]
actions = []
automations = config.get(BinarySensorSchema.CONF_AUTOMATION)
if automations is not None:
for automation in automations:
counter = automation[BinarySensorSchema.CONF_COUNTER]
hook = automation[BinarySensorSchema.CONF_HOOK]
action = automation[BinarySensorSchema.CONF_ACTION]
script_name = f"{device_name} turn ON script"
script = Script(hass, action, script_name, DOMAIN)
action = XknxActionCallback(
knx_module, script.async_run, hook=hook, counter=counter
)
actions.append(action)
return XknxBinarySensor(
knx_module,
@ -265,8 +246,8 @@ def _create_binary_sensor(
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],
reset_after=config.get(BinarySensorSchema.CONF_RESET_AFTER),
actions=actions,
)
@ -287,6 +268,9 @@ def _create_weather(knx_module: XKNX, config: ConfigType) -> XknxWeather:
group_address_brightness_west=config.get(
WeatherSchema.CONF_KNX_BRIGHTNESS_WEST_ADDRESS
),
group_address_brightness_north=config.get(
WeatherSchema.CONF_KNX_BRIGHTNESS_NORTH_ADDRESS
),
group_address_wind_speed=config.get(WeatherSchema.CONF_KNX_WIND_SPEED_ADDRESS),
group_address_rain_alarm=config.get(WeatherSchema.CONF_KNX_RAIN_ALARM_ADDRESS),
group_address_frost_alarm=config.get(

View file

@ -2,6 +2,6 @@
"domain": "knx",
"name": "KNX",
"documentation": "https://www.home-assistant.io/integrations/knx",
"requirements": ["xknx==0.13.0"],
"requirements": ["xknx==0.14.2"],
"codeowners": ["@Julius2342", "@farmio", "@marvin-w"]
}

View file

@ -1,6 +1,7 @@
"""Voluptuous schemas for the KNX integration."""
import voluptuous as vol
from xknx.devices.climate import SetpointShiftMode
from xknx.io import DEFAULT_MCAST_PORT
from homeassistant.const import (
CONF_ADDRESS,
@ -29,9 +30,9 @@ class ConnectionSchema:
TUNNELING_SCHEMA = vol.Schema(
{
vol.Optional(CONF_PORT, default=DEFAULT_MCAST_PORT): cv.port,
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_KNX_LOCAL_IP): cv.string,
vol.Optional(CONF_PORT): cv.port,
}
)
@ -84,27 +85,14 @@ class BinarySensorSchema:
CONF_STATE_ADDRESS = CONF_STATE_ADDRESS
CONF_SYNC_STATE = CONF_SYNC_STATE
CONF_IGNORE_INTERNAL_STATE = "ignore_internal_state"
CONF_AUTOMATION = "automation"
CONF_HOOK = "hook"
CONF_DEFAULT_HOOK = "on"
CONF_COUNTER = "counter"
CONF_DEFAULT_COUNTER = 1
CONF_ACTION = "action"
CONF_CONTEXT_TIMEOUT = "context_timeout"
CONF_RESET_AFTER = "reset_after"
DEFAULT_NAME = "KNX Binary Sensor"
AUTOMATION_SCHEMA = vol.Schema(
{
vol.Optional(CONF_HOOK, default=CONF_DEFAULT_HOOK): cv.string,
vol.Optional(CONF_COUNTER, default=CONF_DEFAULT_COUNTER): cv.port,
vol.Required(CONF_ACTION): cv.SCRIPT_SCHEMA,
}
)
AUTOMATIONS_SCHEMA = vol.All(cv.ensure_list, [AUTOMATION_SCHEMA])
SCHEMA = vol.All(
cv.deprecated("significant_bit"),
cv.deprecated("automation"),
vol.Schema(
{
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@ -113,11 +101,13 @@ class BinarySensorSchema:
cv.boolean,
cv.string,
),
vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=False): cv.boolean,
vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=True): cv.boolean,
vol.Optional(CONF_CONTEXT_TIMEOUT, default=1.0): 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_RESET_AFTER): cv.positive_int,
vol.Optional(CONF_AUTOMATION): AUTOMATIONS_SCHEMA,
}
),
)
@ -350,6 +340,7 @@ class WeatherSchema:
CONF_KNX_BRIGHTNESS_SOUTH_ADDRESS = "address_brightness_south"
CONF_KNX_BRIGHTNESS_EAST_ADDRESS = "address_brightness_east"
CONF_KNX_BRIGHTNESS_WEST_ADDRESS = "address_brightness_west"
CONF_KNX_BRIGHTNESS_NORTH_ADDRESS = "address_brightness_north"
CONF_KNX_WIND_SPEED_ADDRESS = "address_wind_speed"
CONF_KNX_RAIN_ALARM_ADDRESS = "address_rain_alarm"
CONF_KNX_FROST_ALARM_ADDRESS = "address_frost_alarm"
@ -374,6 +365,7 @@ class WeatherSchema:
vol.Optional(CONF_KNX_BRIGHTNESS_SOUTH_ADDRESS): cv.string,
vol.Optional(CONF_KNX_BRIGHTNESS_EAST_ADDRESS): cv.string,
vol.Optional(CONF_KNX_BRIGHTNESS_WEST_ADDRESS): cv.string,
vol.Optional(CONF_KNX_BRIGHTNESS_NORTH_ADDRESS): cv.string,
vol.Optional(CONF_KNX_WIND_SPEED_ADDRESS): cv.string,
vol.Optional(CONF_KNX_RAIN_ALARM_ADDRESS): cv.string,
vol.Optional(CONF_KNX_FROST_ALARM_ADDRESS): cv.string,

View file

@ -1,4 +1,5 @@
"""Support for KNX/IP weather station."""
from xknx.devices import Weather as XknxWeather
from homeassistant.components.weather import WeatherEntity

View file

@ -2265,7 +2265,7 @@ xboxapi==2.0.1
xfinity-gateway==0.0.4
# homeassistant.components.knx
xknx==0.13.0
xknx==0.14.2
# homeassistant.components.bluesound
# homeassistant.components.rest