Bump plugwise to v0.25.12 (#82146)

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
fixes undefined
pull/82665/head
Bouwe Westerdijk 2022-11-25 10:55:51 +01:00 committed by GitHub
parent 9feb64cebd
commit ea1868b7b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 123 additions and 64 deletions

View File

@ -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",

View File

@ -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(

View File

@ -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]),

View File

@ -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")

View File

@ -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,

View File

@ -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%]",

View File

@ -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": {

View File

@ -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

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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"],

View File

@ -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"],

View File

@ -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

View File

@ -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,
)

View File

@ -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(

View File

@ -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)