Reflect changes to pydeconz v84 (#56361)
Mostly snake case conversions and typing But also a change in retry mechanism Added a more complete set_* call to most types to remove the direct relation to rest API of deCONZ
This commit is contained in:
parent
6947912fa9
commit
539ef31046
22 changed files with 87 additions and 85 deletions
|
@ -55,7 +55,7 @@ DECONZ_TO_ALARM_STATE = {
|
||||||
|
|
||||||
def get_alarm_system_for_unique_id(gateway, unique_id: str):
|
def get_alarm_system_for_unique_id(gateway, unique_id: str):
|
||||||
"""Retrieve alarm system unique ID is registered to."""
|
"""Retrieve alarm system unique ID is registered to."""
|
||||||
for alarm_system in gateway.api.alarm_systems.values():
|
for alarm_system in gateway.api.alarmsystems.values():
|
||||||
if unique_id in alarm_system.devices:
|
if unique_id in alarm_system.devices:
|
||||||
return alarm_system
|
return alarm_system
|
||||||
|
|
||||||
|
@ -77,8 +77,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor.type in AncillaryControl.ZHATYPE
|
sensor.type in AncillaryControl.ZHATYPE
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.unique_id not in gateway.entities[DOMAIN]
|
||||||
and get_alarm_system_for_unique_id(gateway, sensor.uniqueid)
|
and get_alarm_system_for_unique_id(gateway, sensor.unique_id)
|
||||||
):
|
):
|
||||||
|
|
||||||
entities.append(DeconzAlarmControlPanel(sensor, gateway))
|
entities.append(DeconzAlarmControlPanel(sensor, gateway))
|
||||||
|
@ -110,7 +110,7 @@ class DeconzAlarmControlPanel(DeconzDevice, AlarmControlPanelEntity):
|
||||||
def __init__(self, device, gateway) -> None:
|
def __init__(self, device, gateway) -> None:
|
||||||
"""Set up alarm control panel device."""
|
"""Set up alarm control panel device."""
|
||||||
super().__init__(device, gateway)
|
super().__init__(device, gateway)
|
||||||
self.alarm_system = get_alarm_system_for_unique_id(gateway, device.uniqueid)
|
self.alarm_system = get_alarm_system_for_unique_id(gateway, device.unique_id)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_callback(self, force_update: bool = False) -> None:
|
def async_update_callback(self, force_update: bool = False) -> None:
|
||||||
|
|
|
@ -48,7 +48,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor.BINARY
|
sensor.BINARY
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.unique_id not in gateway.entities[DOMAIN]
|
||||||
and (
|
and (
|
||||||
gateway.option_allow_clip_sensor
|
gateway.option_allow_clip_sensor
|
||||||
or not sensor.type.startswith("CLIP")
|
or not sensor.type.startswith("CLIP")
|
||||||
|
@ -116,8 +116,8 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
|
||||||
|
|
||||||
elif self._device.type in Vibration.ZHATYPE:
|
elif self._device.type in Vibration.ZHATYPE:
|
||||||
attr[ATTR_ORIENTATION] = self._device.orientation
|
attr[ATTR_ORIENTATION] = self._device.orientation
|
||||||
attr[ATTR_TILTANGLE] = self._device.tiltangle
|
attr[ATTR_TILTANGLE] = self._device.tilt_angle
|
||||||
attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibrationstrength
|
attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibration_strength
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor.type in Thermostat.ZHATYPE
|
sensor.type in Thermostat.ZHATYPE
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.unique_id not in gateway.entities[DOMAIN]
|
||||||
and (
|
and (
|
||||||
gateway.option_allow_clip_sensor
|
gateway.option_allow_clip_sensor
|
||||||
or not sensor.type.startswith("CLIP")
|
or not sensor.type.startswith("CLIP")
|
||||||
|
@ -142,7 +142,7 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||||
def fan_mode(self) -> str:
|
def fan_mode(self) -> str:
|
||||||
"""Return fan operation."""
|
"""Return fan operation."""
|
||||||
return DECONZ_TO_FAN_MODE.get(
|
return DECONZ_TO_FAN_MODE.get(
|
||||||
self._device.fanmode, FAN_ON if self._device.state_on else FAN_OFF
|
self._device.fan_mode, FAN_ON if self._device.state_on else FAN_OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -155,9 +155,7 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||||
if fan_mode not in FAN_MODE_TO_DECONZ:
|
if fan_mode not in FAN_MODE_TO_DECONZ:
|
||||||
raise ValueError(f"Unsupported fan mode {fan_mode}")
|
raise ValueError(f"Unsupported fan mode {fan_mode}")
|
||||||
|
|
||||||
data = {"fanmode": FAN_MODE_TO_DECONZ[fan_mode]}
|
await self._device.set_config(fan_mode=FAN_MODE_TO_DECONZ[fan_mode])
|
||||||
|
|
||||||
await self._device.async_set_config(data)
|
|
||||||
|
|
||||||
# HVAC control
|
# HVAC control
|
||||||
|
|
||||||
|
@ -186,7 +184,7 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||||
if len(self._hvac_mode_to_deconz) == 2: # Only allow turn on and off thermostat
|
if len(self._hvac_mode_to_deconz) == 2: # Only allow turn on and off thermostat
|
||||||
data = {"on": self._hvac_mode_to_deconz[hvac_mode]}
|
data = {"on": self._hvac_mode_to_deconz[hvac_mode]}
|
||||||
|
|
||||||
await self._device.async_set_config(data)
|
await self._device.set_config(**data)
|
||||||
|
|
||||||
# Preset control
|
# Preset control
|
||||||
|
|
||||||
|
@ -205,9 +203,7 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||||
if preset_mode not in PRESET_MODE_TO_DECONZ:
|
if preset_mode not in PRESET_MODE_TO_DECONZ:
|
||||||
raise ValueError(f"Unsupported preset mode {preset_mode}")
|
raise ValueError(f"Unsupported preset mode {preset_mode}")
|
||||||
|
|
||||||
data = {"preset": PRESET_MODE_TO_DECONZ[preset_mode]}
|
await self._device.set_config(preset=PRESET_MODE_TO_DECONZ[preset_mode])
|
||||||
|
|
||||||
await self._device.async_set_config(data)
|
|
||||||
|
|
||||||
# Temperature control
|
# Temperature control
|
||||||
|
|
||||||
|
@ -220,19 +216,19 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||||
def target_temperature(self) -> float:
|
def target_temperature(self) -> float:
|
||||||
"""Return the target temperature."""
|
"""Return the target temperature."""
|
||||||
if self._device.mode == "cool":
|
if self._device.mode == "cool":
|
||||||
return self._device.coolsetpoint
|
return self._device.cooling_setpoint
|
||||||
return self._device.heatsetpoint
|
return self._device.heating_setpoint
|
||||||
|
|
||||||
async def async_set_temperature(self, **kwargs):
|
async def async_set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
if ATTR_TEMPERATURE not in kwargs:
|
if ATTR_TEMPERATURE not in kwargs:
|
||||||
raise ValueError(f"Expected attribute {ATTR_TEMPERATURE}")
|
raise ValueError(f"Expected attribute {ATTR_TEMPERATURE}")
|
||||||
|
|
||||||
data = {"heatsetpoint": kwargs[ATTR_TEMPERATURE] * 100}
|
data = {"heating_setpoint": kwargs[ATTR_TEMPERATURE] * 100}
|
||||||
if self._device.mode == "cool":
|
if self._device.mode == "cool":
|
||||||
data = {"coolsetpoint": kwargs[ATTR_TEMPERATURE] * 100}
|
data = {"cooling_setpoint": kwargs[ATTR_TEMPERATURE] * 100}
|
||||||
|
|
||||||
await self._device.async_set_config(data)
|
await self._device.set_config(**data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self):
|
||||||
|
|
|
@ -5,10 +5,10 @@ from urllib.parse import urlparse
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
from pydeconz.errors import RequestError, ResponseError
|
from pydeconz.errors import RequestError, ResponseError
|
||||||
|
from pydeconz.gateway import DeconzSession
|
||||||
from pydeconz.utils import (
|
from pydeconz.utils import (
|
||||||
async_discovery,
|
discovery as deconz_discovery,
|
||||||
async_get_api_key,
|
get_bridge_id as deconz_get_bridge_id,
|
||||||
async_get_bridge_id,
|
|
||||||
normalize_bridge_id,
|
normalize_bridge_id,
|
||||||
)
|
)
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
@ -86,7 +86,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with async_timeout.timeout(10):
|
with async_timeout.timeout(10):
|
||||||
self.bridges = await async_discovery(session)
|
self.bridges = await deconz_discovery(session)
|
||||||
|
|
||||||
except (asyncio.TimeoutError, ResponseError):
|
except (asyncio.TimeoutError, ResponseError):
|
||||||
self.bridges = []
|
self.bridges = []
|
||||||
|
@ -134,10 +134,15 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
session = aiohttp_client.async_get_clientsession(self.hass)
|
session = aiohttp_client.async_get_clientsession(self.hass)
|
||||||
|
deconz_session = DeconzSession(
|
||||||
|
session,
|
||||||
|
host=self.deconz_config[CONF_HOST],
|
||||||
|
port=self.deconz_config[CONF_PORT],
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with async_timeout.timeout(10):
|
with async_timeout.timeout(10):
|
||||||
api_key = await async_get_api_key(session, **self.deconz_config)
|
api_key = await deconz_session.get_api_key()
|
||||||
|
|
||||||
except (ResponseError, RequestError, asyncio.TimeoutError):
|
except (ResponseError, RequestError, asyncio.TimeoutError):
|
||||||
errors["base"] = "no_key"
|
errors["base"] = "no_key"
|
||||||
|
@ -155,7 +160,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with async_timeout.timeout(10):
|
with async_timeout.timeout(10):
|
||||||
self.bridge_id = await async_get_bridge_id(
|
self.bridge_id = await deconz_get_bridge_id(
|
||||||
session, **self.deconz_config
|
session, **self.deconz_config
|
||||||
)
|
)
|
||||||
await self.async_set_unique_id(self.bridge_id)
|
await self.async_set_unique_id(self.bridge_id)
|
||||||
|
|
|
@ -48,7 +48,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
for light in lights:
|
for light in lights:
|
||||||
if (
|
if (
|
||||||
light.type in COVER_TYPES
|
light.type in COVER_TYPES
|
||||||
and light.uniqueid not in gateway.entities[DOMAIN]
|
and light.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzCover(light, gateway))
|
entities.append(DeconzCover(light, gateway))
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,15 @@ class DeconzBase:
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique identifier for this device."""
|
"""Return a unique identifier for this device."""
|
||||||
return self._device.uniqueid
|
return self._device.unique_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serial(self):
|
def serial(self):
|
||||||
"""Return a serial number for this device."""
|
"""Return a serial number for this device."""
|
||||||
if self._device.uniqueid is None or self._device.uniqueid.count(":") != 7:
|
if self._device.unique_id is None or self._device.unique_id.count(":") != 7:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self._device.uniqueid.split("-", 1)[0]
|
return self._device.unique_id.split("-", 1)[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
|
@ -38,10 +38,10 @@ class DeconzBase:
|
||||||
"connections": {(CONNECTION_ZIGBEE, self.serial)},
|
"connections": {(CONNECTION_ZIGBEE, self.serial)},
|
||||||
"identifiers": {(DECONZ_DOMAIN, self.serial)},
|
"identifiers": {(DECONZ_DOMAIN, self.serial)},
|
||||||
"manufacturer": self._device.manufacturer,
|
"manufacturer": self._device.manufacturer,
|
||||||
"model": self._device.modelid,
|
"model": self._device.model_id,
|
||||||
"name": self._device.name,
|
"name": self._device.name,
|
||||||
"sw_version": self._device.swversion,
|
"sw_version": self._device.software_version,
|
||||||
"via_device": (DECONZ_DOMAIN, self.gateway.api.config.bridgeid),
|
"via_device": (DECONZ_DOMAIN, self.gateway.api.config.bridge_id),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ async def async_setup_events(gateway) -> None:
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor.type not in Switch.ZHATYPE + AncillaryControl.ZHATYPE
|
sensor.type not in Switch.ZHATYPE + AncillaryControl.ZHATYPE
|
||||||
or sensor.uniqueid in {event.unique_id for event in gateway.events}
|
or sensor.unique_id in {event.unique_id for event in gateway.events}
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
||||||
|
|
||||||
for light in lights:
|
for light in lights:
|
||||||
|
|
||||||
if light.type in FANS and light.uniqueid not in gateway.entities[DOMAIN]:
|
if light.type in FANS and light.unique_id not in gateway.entities[DOMAIN]:
|
||||||
entities.append(DeconzFan(light, gateway))
|
entities.append(DeconzFan(light, gateway))
|
||||||
|
|
||||||
if entities:
|
if entities:
|
||||||
|
|
|
@ -151,11 +151,11 @@ class DeconzGateway:
|
||||||
# Gateway service
|
# Gateway service
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
config_entry_id=self.config_entry.entry_id,
|
config_entry_id=self.config_entry.entry_id,
|
||||||
identifiers={(DECONZ_DOMAIN, self.api.config.bridgeid)},
|
identifiers={(DECONZ_DOMAIN, self.api.config.bridge_id)},
|
||||||
manufacturer="Dresden Elektronik",
|
manufacturer="Dresden Elektronik",
|
||||||
model=self.api.config.modelid,
|
model=self.api.config.model_id,
|
||||||
name=self.api.config.name,
|
name=self.api.config.name,
|
||||||
sw_version=self.api.config.swversion,
|
sw_version=self.api.config.software_version,
|
||||||
via_device=(CONNECTION_NETWORK_MAC, self.api.config.mac),
|
via_device=(CONNECTION_NETWORK_MAC, self.api.config.mac),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -266,12 +266,12 @@ async def get_gateway(
|
||||||
config[CONF_HOST],
|
config[CONF_HOST],
|
||||||
config[CONF_PORT],
|
config[CONF_PORT],
|
||||||
config[CONF_API_KEY],
|
config[CONF_API_KEY],
|
||||||
async_add_device=async_add_device_callback,
|
add_device=async_add_device_callback,
|
||||||
connection_status=async_connection_status_callback,
|
connection_status=async_connection_status_callback,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with async_timeout.timeout(10):
|
with async_timeout.timeout(10):
|
||||||
await deconz.initialize()
|
await deconz.refresh_state()
|
||||||
return deconz
|
return deconz
|
||||||
|
|
||||||
except errors.Unauthorized as err:
|
except errors.Unauthorized as err:
|
||||||
|
|
|
@ -58,7 +58,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
for light in lights:
|
for light in lights:
|
||||||
if (
|
if (
|
||||||
light.type not in other_light_resource_types
|
light.type not in other_light_resource_types
|
||||||
and light.uniqueid not in gateway.entities[DOMAIN]
|
and light.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzLight(light, gateway))
|
entities.append(DeconzLight(light, gateway))
|
||||||
|
|
||||||
|
@ -112,10 +112,10 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
|
|
||||||
self._attr_supported_color_modes = set()
|
self._attr_supported_color_modes = set()
|
||||||
|
|
||||||
if device.ct is not None:
|
if device.color_temp is not None:
|
||||||
self._attr_supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
|
self._attr_supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
|
||||||
|
|
||||||
if device.hue is not None and device.sat is not None:
|
if device.hue is not None and device.saturation is not None:
|
||||||
self._attr_supported_color_modes.add(COLOR_MODE_HS)
|
self._attr_supported_color_modes.add(COLOR_MODE_HS)
|
||||||
|
|
||||||
if device.xy is not None:
|
if device.xy is not None:
|
||||||
|
@ -137,11 +137,11 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
@property
|
@property
|
||||||
def color_mode(self) -> str:
|
def color_mode(self) -> str:
|
||||||
"""Return the color mode of the light."""
|
"""Return the color mode of the light."""
|
||||||
if self._device.colormode == "ct":
|
if self._device.color_mode == "ct":
|
||||||
color_mode = COLOR_MODE_COLOR_TEMP
|
color_mode = COLOR_MODE_COLOR_TEMP
|
||||||
elif self._device.colormode == "hs":
|
elif self._device.color_mode == "hs":
|
||||||
color_mode = COLOR_MODE_HS
|
color_mode = COLOR_MODE_HS
|
||||||
elif self._device.colormode == "xy":
|
elif self._device.color_mode == "xy":
|
||||||
color_mode = COLOR_MODE_XY
|
color_mode = COLOR_MODE_XY
|
||||||
elif self._device.brightness is not None:
|
elif self._device.brightness is not None:
|
||||||
color_mode = COLOR_MODE_BRIGHTNESS
|
color_mode = COLOR_MODE_BRIGHTNESS
|
||||||
|
@ -162,12 +162,12 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
@property
|
@property
|
||||||
def color_temp(self):
|
def color_temp(self):
|
||||||
"""Return the CT color value."""
|
"""Return the CT color value."""
|
||||||
return self._device.ct
|
return self._device.color_temp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hs_color(self) -> tuple:
|
def hs_color(self) -> tuple:
|
||||||
"""Return the hs color value."""
|
"""Return the hs color value."""
|
||||||
return (self._device.hue / 65535 * 360, self._device.sat / 255 * 100)
|
return (self._device.hue / 65535 * 360, self._device.saturation / 255 * 100)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def xy_color(self) -> tuple | None:
|
def xy_color(self) -> tuple | None:
|
||||||
|
@ -184,25 +184,25 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
data = {"on": True}
|
data = {"on": True}
|
||||||
|
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
if ATTR_BRIGHTNESS in kwargs:
|
||||||
data["bri"] = kwargs[ATTR_BRIGHTNESS]
|
data["brightness"] = kwargs[ATTR_BRIGHTNESS]
|
||||||
|
|
||||||
if ATTR_COLOR_TEMP in kwargs:
|
if ATTR_COLOR_TEMP in kwargs:
|
||||||
data["ct"] = kwargs[ATTR_COLOR_TEMP]
|
data["color_temperature"] = kwargs[ATTR_COLOR_TEMP]
|
||||||
|
|
||||||
if ATTR_HS_COLOR in kwargs:
|
if ATTR_HS_COLOR in kwargs:
|
||||||
if COLOR_MODE_XY in self._attr_supported_color_modes:
|
if COLOR_MODE_XY in self._attr_supported_color_modes:
|
||||||
data["xy"] = color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
|
data["xy"] = color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
|
||||||
else:
|
else:
|
||||||
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
|
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
|
||||||
data["sat"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
|
data["saturation"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
|
||||||
|
|
||||||
if ATTR_XY_COLOR in kwargs:
|
if ATTR_XY_COLOR in kwargs:
|
||||||
data["xy"] = kwargs[ATTR_XY_COLOR]
|
data["xy"] = kwargs[ATTR_XY_COLOR]
|
||||||
|
|
||||||
if ATTR_TRANSITION in kwargs:
|
if ATTR_TRANSITION in kwargs:
|
||||||
data["transitiontime"] = int(kwargs[ATTR_TRANSITION] * 10)
|
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
|
||||||
elif "IKEA" in self._device.manufacturer:
|
elif "IKEA" in self._device.manufacturer:
|
||||||
data["transitiontime"] = 0
|
data["transition_time"] = 0
|
||||||
|
|
||||||
if ATTR_FLASH in kwargs:
|
if ATTR_FLASH in kwargs:
|
||||||
if kwargs[ATTR_FLASH] == FLASH_SHORT:
|
if kwargs[ATTR_FLASH] == FLASH_SHORT:
|
||||||
|
@ -218,7 +218,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
else:
|
else:
|
||||||
data["effect"] = "none"
|
data["effect"] = "none"
|
||||||
|
|
||||||
await self._device.async_set_state(data)
|
await self._device.set_state(**data)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn off light."""
|
"""Turn off light."""
|
||||||
|
@ -228,8 +228,8 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
data = {"on": False}
|
data = {"on": False}
|
||||||
|
|
||||||
if ATTR_TRANSITION in kwargs:
|
if ATTR_TRANSITION in kwargs:
|
||||||
data["bri"] = 0
|
data["brightness"] = 0
|
||||||
data["transitiontime"] = int(kwargs[ATTR_TRANSITION] * 10)
|
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
|
||||||
|
|
||||||
if ATTR_FLASH in kwargs:
|
if ATTR_FLASH in kwargs:
|
||||||
if kwargs[ATTR_FLASH] == FLASH_SHORT:
|
if kwargs[ATTR_FLASH] == FLASH_SHORT:
|
||||||
|
@ -239,7 +239,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||||
data["alert"] = "lselect"
|
data["alert"] = "lselect"
|
||||||
del data["on"]
|
del data["on"]
|
||||||
|
|
||||||
await self._device.async_set_state(data)
|
await self._device.set_state(**data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self):
|
||||||
|
@ -253,12 +253,12 @@ class DeconzLight(DeconzBaseLight):
|
||||||
@property
|
@property
|
||||||
def max_mireds(self):
|
def max_mireds(self):
|
||||||
"""Return the warmest color_temp that this light supports."""
|
"""Return the warmest color_temp that this light supports."""
|
||||||
return self._device.ctmax or super().max_mireds
|
return self._device.max_color_temp or super().max_mireds
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_mireds(self):
|
def min_mireds(self):
|
||||||
"""Return the coldest color_temp that this light supports."""
|
"""Return the coldest color_temp that this light supports."""
|
||||||
return self._device.ctmin or super().min_mireds
|
return self._device.min_color_temp or super().min_mireds
|
||||||
|
|
||||||
|
|
||||||
class DeconzGroup(DeconzBaseLight):
|
class DeconzGroup(DeconzBaseLight):
|
||||||
|
@ -282,7 +282,7 @@ class DeconzGroup(DeconzBaseLight):
|
||||||
"manufacturer": "Dresden Elektronik",
|
"manufacturer": "Dresden Elektronik",
|
||||||
"model": "deCONZ group",
|
"model": "deCONZ group",
|
||||||
"name": self._device.name,
|
"name": self._device.name,
|
||||||
"via_device": (DECONZ_DOMAIN, self.gateway.api.config.bridgeid),
|
"via_device": (DECONZ_DOMAIN, self.gateway.api.config.bridge_id),
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -22,7 +22,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
light.type in LOCK_TYPES
|
light.type in LOCK_TYPES
|
||||||
and light.uniqueid not in gateway.entities[DOMAIN]
|
and light.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzLock(light, gateway))
|
entities.append(DeconzLock(light, gateway))
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor.type in LOCK_TYPES
|
sensor.type in LOCK_TYPES
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzLock(sensor, gateway))
|
entities.append(DeconzLock(sensor, gateway))
|
||||||
|
|
||||||
|
|
|
@ -153,9 +153,9 @@ def async_describe_events(
|
||||||
interface = None
|
interface = None
|
||||||
data = event.data.get(CONF_EVENT) or event.data.get(CONF_GESTURE, "")
|
data = event.data.get(CONF_EVENT) or event.data.get(CONF_GESTURE, "")
|
||||||
|
|
||||||
if data and deconz_event.device.modelid in REMOTES:
|
if data and deconz_event.device.model_id in REMOTES:
|
||||||
action, interface = _get_device_event_description(
|
action, interface = _get_device_event_description(
|
||||||
deconz_event.device.modelid, data
|
deconz_event.device.model_id, data
|
||||||
)
|
)
|
||||||
|
|
||||||
# Unknown event
|
# Unknown event
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/deconz",
|
"documentation": "https://www.home-assistant.io/integrations/deconz",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"pydeconz==83"
|
"pydeconz==84"
|
||||||
],
|
],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,4 +51,4 @@ class DeconzScene(Scene):
|
||||||
|
|
||||||
async def async_activate(self, **kwargs: Any) -> None:
|
async def async_activate(self, **kwargs: Any) -> None:
|
||||||
"""Activate the scene."""
|
"""Activate the scene."""
|
||||||
await self._scene.async_set_state({})
|
await self._scene.recall()
|
||||||
|
|
|
@ -124,7 +124,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
+ DoorLock.ZHATYPE
|
+ DoorLock.ZHATYPE
|
||||||
+ Switch.ZHATYPE
|
+ Switch.ZHATYPE
|
||||||
+ Thermostat.ZHATYPE
|
+ Thermostat.ZHATYPE
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzSensor(sensor, gateway))
|
entities.append(DeconzSensor(sensor, gateway))
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ class DeconzBattery(DeconzDevice, SensorEntity):
|
||||||
Normally there should only be one battery sensor per device from deCONZ.
|
Normally there should only be one battery sensor per device from deCONZ.
|
||||||
With specific Danfoss devices each endpoint can report its own battery state.
|
With specific Danfoss devices each endpoint can report its own battery state.
|
||||||
"""
|
"""
|
||||||
if self._device.manufacturer == "Danfoss" and self._device.modelid in [
|
if self._device.manufacturer == "Danfoss" and self._device.model_id in [
|
||||||
"0x8030",
|
"0x8030",
|
||||||
"0x8031",
|
"0x8031",
|
||||||
"0x8034",
|
"0x8034",
|
||||||
|
|
|
@ -185,7 +185,7 @@ async def async_remove_orphaned_entries_service(gateway):
|
||||||
|
|
||||||
# Don't remove the Gateway service entry
|
# Don't remove the Gateway service entry
|
||||||
gateway_service = device_registry.async_get_device(
|
gateway_service = device_registry.async_get_device(
|
||||||
identifiers={(DOMAIN, gateway.api.config.bridgeid)}, connections=set()
|
identifiers={(DOMAIN, gateway.api.config.bridge_id)}, connections=set()
|
||||||
)
|
)
|
||||||
if gateway_service.id in devices_to_be_removed:
|
if gateway_service.id in devices_to_be_removed:
|
||||||
devices_to_be_removed.remove(gateway_service.id)
|
devices_to_be_removed.remove(gateway_service.id)
|
||||||
|
|
|
@ -25,12 +25,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
light.type in POWER_PLUGS
|
light.type in POWER_PLUGS
|
||||||
and light.uniqueid not in gateway.entities[DOMAIN]
|
and light.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzPowerPlug(light, gateway))
|
entities.append(DeconzPowerPlug(light, gateway))
|
||||||
|
|
||||||
elif (
|
elif (
|
||||||
light.type in SIRENS and light.uniqueid not in gateway.entities[DOMAIN]
|
light.type in SIRENS and light.unique_id not in gateway.entities[DOMAIN]
|
||||||
):
|
):
|
||||||
entities.append(DeconzSiren(light, gateway))
|
entities.append(DeconzSiren(light, gateway))
|
||||||
|
|
||||||
|
@ -58,13 +58,11 @@ class DeconzPowerPlug(DeconzDevice, SwitchEntity):
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn on switch."""
|
"""Turn on switch."""
|
||||||
data = {"on": True}
|
await self._device.set_state(on=True)
|
||||||
await self._device.async_set_state(data)
|
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn off switch."""
|
"""Turn off switch."""
|
||||||
data = {"on": False}
|
await self._device.set_state(on=False)
|
||||||
await self._device.async_set_state(data)
|
|
||||||
|
|
||||||
|
|
||||||
class DeconzSiren(DeconzDevice, SwitchEntity):
|
class DeconzSiren(DeconzDevice, SwitchEntity):
|
||||||
|
|
|
@ -1415,7 +1415,7 @@ pydaikin==2.4.4
|
||||||
pydanfossair==0.1.0
|
pydanfossair==0.1.0
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==83
|
pydeconz==84
|
||||||
|
|
||||||
# homeassistant.components.delijn
|
# homeassistant.components.delijn
|
||||||
pydelijn==0.6.1
|
pydelijn==0.6.1
|
||||||
|
|
|
@ -815,7 +815,7 @@ pycoolmasternet-async==0.1.2
|
||||||
pydaikin==2.4.4
|
pydaikin==2.4.4
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==83
|
pydeconz==84
|
||||||
|
|
||||||
# homeassistant.components.dexcom
|
# homeassistant.components.dexcom
|
||||||
pydexcom==0.2.0
|
pydexcom==0.2.0
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pydeconz.websocket import SIGNAL_CONNECTION_STATE, SIGNAL_DATA
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.components.light.conftest import mock_light_profiles # noqa: F401
|
from tests.components.light.conftest import mock_light_profiles # noqa: F401
|
||||||
|
@ -19,10 +20,10 @@ def mock_deconz_websocket():
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
mock.return_value.data = data
|
mock.return_value.data = data
|
||||||
await pydeconz_gateway_session_handler(signal="data")
|
await pydeconz_gateway_session_handler(signal=SIGNAL_DATA)
|
||||||
elif state:
|
elif state:
|
||||||
mock.return_value.state = state
|
mock.return_value.state = state
|
||||||
await pydeconz_gateway_session_handler(signal="state")
|
await pydeconz_gateway_session_handler(signal=SIGNAL_CONNECTION_STATE)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
@ -267,14 +267,14 @@ async def test_reset_after_successful_setup(hass, aioclient_mock):
|
||||||
|
|
||||||
async def test_get_gateway(hass):
|
async def test_get_gateway(hass):
|
||||||
"""Successful call."""
|
"""Successful call."""
|
||||||
with patch("pydeconz.DeconzSession.initialize", return_value=True):
|
with patch("pydeconz.DeconzSession.refresh_state", return_value=True):
|
||||||
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock())
|
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock())
|
||||||
|
|
||||||
|
|
||||||
async def test_get_gateway_fails_unauthorized(hass):
|
async def test_get_gateway_fails_unauthorized(hass):
|
||||||
"""Failed call."""
|
"""Failed call."""
|
||||||
with patch(
|
with patch(
|
||||||
"pydeconz.DeconzSession.initialize",
|
"pydeconz.DeconzSession.refresh_state",
|
||||||
side_effect=pydeconz.errors.Unauthorized,
|
side_effect=pydeconz.errors.Unauthorized,
|
||||||
), pytest.raises(AuthenticationRequired):
|
), pytest.raises(AuthenticationRequired):
|
||||||
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock()) is False
|
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock()) is False
|
||||||
|
@ -283,7 +283,7 @@ async def test_get_gateway_fails_unauthorized(hass):
|
||||||
async def test_get_gateway_fails_cannot_connect(hass):
|
async def test_get_gateway_fails_cannot_connect(hass):
|
||||||
"""Failed call."""
|
"""Failed call."""
|
||||||
with patch(
|
with patch(
|
||||||
"pydeconz.DeconzSession.initialize",
|
"pydeconz.DeconzSession.refresh_state",
|
||||||
side_effect=pydeconz.errors.RequestError,
|
side_effect=pydeconz.errors.RequestError,
|
||||||
), pytest.raises(CannotConnect):
|
), pytest.raises(CannotConnect):
|
||||||
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock()) is False
|
assert await get_gateway(hass, ENTRY_CONFIG, Mock(), Mock()) is False
|
||||||
|
|
|
@ -44,14 +44,16 @@ async def setup_entry(hass, entry):
|
||||||
|
|
||||||
async def test_setup_entry_fails(hass):
|
async def test_setup_entry_fails(hass):
|
||||||
"""Test setup entry fails if deCONZ is not available."""
|
"""Test setup entry fails if deCONZ is not available."""
|
||||||
with patch("pydeconz.DeconzSession.initialize", side_effect=Exception):
|
with patch("pydeconz.DeconzSession.refresh_state", side_effect=Exception):
|
||||||
await setup_deconz_integration(hass)
|
await setup_deconz_integration(hass)
|
||||||
assert not hass.data[DECONZ_DOMAIN]
|
assert not hass.data[DECONZ_DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_entry_no_available_bridge(hass):
|
async def test_setup_entry_no_available_bridge(hass):
|
||||||
"""Test setup entry fails if deCONZ is not available."""
|
"""Test setup entry fails if deCONZ is not available."""
|
||||||
with patch("pydeconz.DeconzSession.initialize", side_effect=asyncio.TimeoutError):
|
with patch(
|
||||||
|
"pydeconz.DeconzSession.refresh_state", side_effect=asyncio.TimeoutError
|
||||||
|
):
|
||||||
await setup_deconz_integration(hass)
|
await setup_deconz_integration(hass)
|
||||||
assert not hass.data[DECONZ_DOMAIN]
|
assert not hass.data[DECONZ_DOMAIN]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue