Bump plugwise to v0.25.12 (#82146)
Co-authored-by: Franck Nijhof <frenck@frenck.nl> fixes undefinedpull/82665/head
parent
9feb64cebd
commit
ea1868b7b9
|
@ -36,6 +36,12 @@ BINARY_SENSORS: tuple[PlugwiseBinarySensorEntityDescription, ...] = (
|
|||
icon_off="mdi:hvac-off",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
PlugwiseBinarySensorEntityDescription(
|
||||
key="cooling_enabled",
|
||||
name="Cooling enabled",
|
||||
icon="mdi:snowflake-thermometer",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
PlugwiseBinarySensorEntityDescription(
|
||||
key="dhw_state",
|
||||
name="DHW state",
|
||||
|
|
|
@ -4,9 +4,12 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidSetupError,
|
||||
PlugwiseException,
|
||||
InvalidXMLError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
from plugwise.smile import Smile
|
||||
import voluptuous as vol
|
||||
|
@ -32,7 +35,6 @@ from .const import (
|
|||
DOMAIN,
|
||||
FLOW_SMILE,
|
||||
FLOW_STRETCH,
|
||||
LOGGER,
|
||||
PW_TYPE,
|
||||
SMILE,
|
||||
STRETCH,
|
||||
|
@ -175,14 +177,17 @@ class PlugwiseConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
|
||||
try:
|
||||
api = await validate_gw_input(self.hass, user_input)
|
||||
except InvalidSetupError:
|
||||
errors[CONF_BASE] = "invalid_setup"
|
||||
except ConnectionFailedError:
|
||||
errors[CONF_BASE] = "cannot_connect"
|
||||
except InvalidAuthentication:
|
||||
errors[CONF_BASE] = "invalid_auth"
|
||||
except PlugwiseException:
|
||||
errors[CONF_BASE] = "cannot_connect"
|
||||
except InvalidSetupError:
|
||||
errors[CONF_BASE] = "invalid_setup"
|
||||
except (InvalidXMLError, ResponseError):
|
||||
errors[CONF_BASE] = "response_error"
|
||||
except UnsupportedDeviceError:
|
||||
errors[CONF_BASE] = "unsupported"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
LOGGER.exception("Unexpected exception")
|
||||
errors[CONF_BASE] = "unknown"
|
||||
else:
|
||||
await self.async_set_unique_id(
|
||||
|
|
|
@ -4,7 +4,13 @@ from typing import NamedTuple, cast
|
|||
|
||||
from plugwise import Smile
|
||||
from plugwise.constants import DeviceData, GatewayData
|
||||
from plugwise.exceptions import PlugwiseException, XMLDataMissingError
|
||||
from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidXMLError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
|
@ -47,12 +53,16 @@ class PlugwiseDataUpdateCoordinator(DataUpdateCoordinator[PlugwiseData]):
|
|||
"""Fetch data from Plugwise."""
|
||||
try:
|
||||
data = await self.api.async_update()
|
||||
except XMLDataMissingError as err:
|
||||
except InvalidAuthentication as err:
|
||||
raise UpdateFailed("Authentication failed") from err
|
||||
except (InvalidXMLError, ResponseError) as err:
|
||||
raise UpdateFailed(
|
||||
f"No XML data received for: {self.api.smile_name}"
|
||||
"Invalid XML data, or error indication received for the Plugwise Adam/Smile/Stretch"
|
||||
) from err
|
||||
except PlugwiseException as err:
|
||||
raise UpdateFailed(f"Updated failed for: {self.api.smile_name}") from err
|
||||
except UnsupportedDeviceError as err:
|
||||
raise UpdateFailed("Device with unsupported firmware") from err
|
||||
except ConnectionFailedError as err:
|
||||
raise UpdateFailed("Failed to connect") from err
|
||||
return PlugwiseData(
|
||||
gateway=cast(GatewayData, data[0]),
|
||||
devices=cast(dict[str, DeviceData], data[1]),
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
"""Plugwise platform for Home Assistant Core."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from aiohttp import ClientConnectionError
|
||||
from plugwise.exceptions import InvalidAuthentication, PlugwiseException
|
||||
from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidXMLError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
from plugwise.smile import Smile
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
|
@ -42,17 +46,16 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
try:
|
||||
connected = await api.connect()
|
||||
except InvalidAuthentication:
|
||||
LOGGER.error("Invalid username or Smile ID")
|
||||
return False
|
||||
except (ClientConnectionError, PlugwiseException) as err:
|
||||
except ConnectionFailedError as err:
|
||||
raise ConfigEntryNotReady("Failed to connect to the Plugwise Smile") from err
|
||||
except InvalidAuthentication as err:
|
||||
raise HomeAssistantError("Invalid username or Smile ID") from err
|
||||
except (InvalidXMLError, ResponseError) as err:
|
||||
raise ConfigEntryNotReady(
|
||||
f"Error while communicating to device {api.smile_name}"
|
||||
) from err
|
||||
except asyncio.TimeoutError as err:
|
||||
raise ConfigEntryNotReady(
|
||||
f"Timeout while connecting to Smile {api.smile_name}"
|
||||
"Error while communicating to the Plugwise Smile"
|
||||
) from err
|
||||
except UnsupportedDeviceError as err:
|
||||
raise HomeAssistantError("Device with unsupported firmware") from err
|
||||
|
||||
if not connected:
|
||||
raise ConfigEntryNotReady("Unable to connect to Smile")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "plugwise",
|
||||
"name": "Plugwise",
|
||||
"documentation": "https://www.home-assistant.io/integrations/plugwise",
|
||||
"requirements": ["plugwise==0.25.7"],
|
||||
"requirements": ["plugwise==0.25.12"],
|
||||
"codeowners": ["@CoMPaTech", "@bouwew", "@brefra", "@frenck"],
|
||||
"zeroconf": ["_plugwise._tcp.local."],
|
||||
"config_flow": true,
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"invalid_setup": "Add your Adam instead of your Anna, see the Home Assistant Plugwise integration documentation for more information",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
"invalid_setup": "Add your Adam instead of your Anna, see the documentation",
|
||||
"response_error": "Invalid XML data, or error indication received",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||
"unsupported": "Device with unsupported firmware"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
"error": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
"invalid_auth": "Invalid authentication",
|
||||
"invalid_setup": "Add your Adam instead of your Anna, see the Home Assistant Plugwise integration documentation for more information",
|
||||
"unknown": "Unexpected error"
|
||||
"invalid_setup": "Add your Adam instead of your Anna, see the documentation",
|
||||
"response_error": "Invalid XML data, or error indication received",
|
||||
"unknown": "Unexpected error",
|
||||
"unsupported": "Device with unsupported firmware"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
|
|
|
@ -1329,7 +1329,7 @@ plexauth==0.0.6
|
|||
plexwebsocket==0.0.13
|
||||
|
||||
# homeassistant.components.plugwise
|
||||
plugwise==0.25.7
|
||||
plugwise==0.25.12
|
||||
|
||||
# homeassistant.components.plum_lightpad
|
||||
plumlightpad==0.0.11
|
||||
|
|
|
@ -956,7 +956,7 @@ plexauth==0.0.6
|
|||
plexwebsocket==0.0.13
|
||||
|
||||
# homeassistant.components.plugwise
|
||||
plugwise==0.25.7
|
||||
plugwise==0.25.12
|
||||
|
||||
# homeassistant.components.plum_lightpad
|
||||
plumlightpad==0.0.11
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"smile_name": "Smile Anna",
|
||||
"gateway_id": "015ae9ea3f964e668e490fa39da3870b",
|
||||
"heater_id": "1cbf783bb11e4a7c8a6843dee3a86927",
|
||||
"cooling_present": true,
|
||||
"cooling_present": false,
|
||||
"notifications": {}
|
||||
},
|
||||
{
|
||||
|
@ -21,10 +21,10 @@
|
|||
},
|
||||
"available": true,
|
||||
"binary_sensors": {
|
||||
"cooling_enabled": false,
|
||||
"dhw_state": false,
|
||||
"heating_state": true,
|
||||
"compressor_state": true,
|
||||
"cooling_state": false,
|
||||
"slave_boiler_state": false,
|
||||
"flame_state": false
|
||||
},
|
||||
|
@ -66,13 +66,11 @@
|
|||
"name": "Anna",
|
||||
"vendor": "Plugwise",
|
||||
"thermostat": {
|
||||
"setpoint_low": 20.5,
|
||||
"setpoint_high": 24.0,
|
||||
"setpoint": 20.5,
|
||||
"lower_bound": 4.0,
|
||||
"upper_bound": 30.0,
|
||||
"resolution": 0.1
|
||||
},
|
||||
"available": true,
|
||||
"preset_modes": ["no_frost", "home", "away", "asleep", "vacation"],
|
||||
"active_preset": "home",
|
||||
"available_schedules": ["standaard"],
|
||||
|
@ -81,11 +79,10 @@
|
|||
"mode": "auto",
|
||||
"sensors": {
|
||||
"temperature": 19.3,
|
||||
"setpoint": 20.5,
|
||||
"illuminance": 86.0,
|
||||
"cooling_activation_outdoor_temperature": 21.0,
|
||||
"cooling_deactivation_threshold": 4.0,
|
||||
"setpoint_low": 20.5,
|
||||
"setpoint_high": 24.0
|
||||
"cooling_deactivation_threshold": 4.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"available": true,
|
||||
"binary_sensors": {
|
||||
"cooling_enabled": true,
|
||||
"dhw_state": false,
|
||||
"heating_state": false,
|
||||
"compressor_state": true,
|
||||
|
@ -72,7 +73,6 @@
|
|||
"upper_bound": 30.0,
|
||||
"resolution": 0.1
|
||||
},
|
||||
"available": true,
|
||||
"preset_modes": ["no_frost", "home", "away", "asleep", "vacation"],
|
||||
"active_preset": "home",
|
||||
"available_schedules": ["standaard"],
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"available": true,
|
||||
"binary_sensors": {
|
||||
"cooling_enabled": true,
|
||||
"dhw_state": false,
|
||||
"heating_state": false,
|
||||
"compressor_state": false,
|
||||
|
@ -72,7 +73,6 @@
|
|||
"upper_bound": 30.0,
|
||||
"resolution": 0.1
|
||||
},
|
||||
"available": true,
|
||||
"preset_modes": ["no_frost", "home", "away", "asleep", "vacation"],
|
||||
"active_preset": "home",
|
||||
"available_schedules": ["standaard"],
|
||||
|
|
|
@ -26,7 +26,7 @@ async def test_anna_climate_binary_sensor_entities(
|
|||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
state = hass.states.get("binary_sensor.opentherm_cooling")
|
||||
state = hass.states.get("binary_sensor.opentherm_cooling_enabled")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ async def test_anna_climate_entity_attributes(
|
|||
assert state.state == HVACMode.AUTO
|
||||
assert state.attributes["hvac_action"] == "heating"
|
||||
assert state.attributes["hvac_modes"] == [
|
||||
HVACMode.HEAT_COOL,
|
||||
HVACMode.HEAT,
|
||||
HVACMode.AUTO,
|
||||
]
|
||||
|
||||
|
@ -211,9 +211,8 @@ async def test_anna_climate_entity_attributes(
|
|||
|
||||
assert state.attributes["current_temperature"] == 19.3
|
||||
assert state.attributes["preset_mode"] == "home"
|
||||
assert state.attributes["supported_features"] == 18
|
||||
assert state.attributes["target_temp_high"] == 24.0
|
||||
assert state.attributes["target_temp_low"] == 20.5
|
||||
assert state.attributes["supported_features"] == 17
|
||||
assert state.attributes["temperature"] == 20.5
|
||||
assert state.attributes["min_temp"] == 4.0
|
||||
assert state.attributes["max_temp"] == 30.0
|
||||
assert state.attributes["target_temp_step"] == 0.1
|
||||
|
@ -286,7 +285,7 @@ async def test_anna_climate_entity_climate_changes(
|
|||
await hass.services.async_call(
|
||||
"climate",
|
||||
"set_hvac_mode",
|
||||
{"entity_id": "climate.anna", "hvac_mode": "heat_cool"},
|
||||
{"entity_id": "climate.anna", "hvac_mode": "heat"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ from plugwise.exceptions import (
|
|||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidSetupError,
|
||||
PlugwiseException,
|
||||
InvalidXMLError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
import pytest
|
||||
|
||||
|
@ -97,9 +99,12 @@ def mock_smile():
|
|||
with patch(
|
||||
"homeassistant.components.plugwise.config_flow.Smile",
|
||||
) as smile_mock:
|
||||
smile_mock.PlugwiseException = PlugwiseException
|
||||
smile_mock.InvalidAuthentication = InvalidAuthentication
|
||||
smile_mock.ConnectionFailedError = ConnectionFailedError
|
||||
smile_mock.InvalidAuthentication = InvalidAuthentication
|
||||
smile_mock.InvalidSetupError = InvalidSetupError
|
||||
smile_mock.InvalidXMLError = InvalidXMLError
|
||||
smile_mock.ResponseError = ResponseError
|
||||
smile_mock.UnsupportedDeviceError = UnsupportedDeviceError
|
||||
smile_mock.return_value.connect.return_value = True
|
||||
yield smile_mock.return_value
|
||||
|
||||
|
@ -266,13 +271,15 @@ async def test_zercoconf_discovery_update_configuration(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"side_effect,reason",
|
||||
"side_effect, reason",
|
||||
[
|
||||
(ConnectionFailedError, "cannot_connect"),
|
||||
(InvalidAuthentication, "invalid_auth"),
|
||||
(InvalidSetupError, "invalid_setup"),
|
||||
(ConnectionFailedError, "cannot_connect"),
|
||||
(PlugwiseException, "cannot_connect"),
|
||||
(InvalidXMLError, "response_error"),
|
||||
(ResponseError, "response_error"),
|
||||
(RuntimeError, "unknown"),
|
||||
(UnsupportedDeviceError, "unsupported"),
|
||||
],
|
||||
)
|
||||
async def test_flow_errors(
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
"""Tests for the Plugwise Climate integration."""
|
||||
import asyncio
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import aiohttp
|
||||
from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
PlugwiseException,
|
||||
XMLDataMissingError,
|
||||
InvalidAuthentication,
|
||||
InvalidXMLError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
import pytest
|
||||
|
||||
|
@ -43,24 +43,52 @@ async def test_load_unload_config_entry(
|
|||
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"side_effect, entry_state",
|
||||
[
|
||||
(ConnectionFailedError, ConfigEntryState.SETUP_RETRY),
|
||||
(InvalidAuthentication, ConfigEntryState.SETUP_ERROR),
|
||||
(InvalidXMLError, ConfigEntryState.SETUP_RETRY),
|
||||
(ResponseError, ConfigEntryState.SETUP_RETRY),
|
||||
(UnsupportedDeviceError, ConfigEntryState.SETUP_ERROR),
|
||||
],
|
||||
)
|
||||
async def test_gateway_config_entry_not_ready(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_smile_anna: MagicMock,
|
||||
side_effect: Exception,
|
||||
entry_state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test the Plugwise configuration entry not ready."""
|
||||
mock_smile_anna.connect.side_effect = side_effect
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_smile_anna.connect.mock_calls) == 1
|
||||
assert mock_config_entry.state is entry_state
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"side_effect",
|
||||
[
|
||||
(ConnectionFailedError),
|
||||
(PlugwiseException),
|
||||
(XMLDataMissingError),
|
||||
(asyncio.TimeoutError),
|
||||
(aiohttp.ClientConnectionError),
|
||||
(InvalidAuthentication),
|
||||
(InvalidXMLError),
|
||||
(ResponseError),
|
||||
(UnsupportedDeviceError),
|
||||
],
|
||||
)
|
||||
async def test_config_entry_not_ready(
|
||||
async def test_coord_config_entry_not_ready(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_smile_anna: MagicMock,
|
||||
side_effect: Exception,
|
||||
) -> None:
|
||||
"""Test the Plugwise configuration entry not ready."""
|
||||
mock_smile_anna.connect.side_effect = side_effect
|
||||
mock_smile_anna.async_update.side_effect = side_effect
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
|
Loading…
Reference in New Issue