diff --git a/homeassistant/components/apcupsd/sensor.py b/homeassistant/components/apcupsd/sensor.py index d30625ee793..bf1b8bf6db5 100644 --- a/homeassistant/components/apcupsd/sensor.py +++ b/homeassistant/components/apcupsd/sensor.py @@ -26,72 +26,72 @@ _LOGGER = logging.getLogger(__name__) SENSOR_PREFIX = "UPS " SENSOR_TYPES = { - "alarmdel": ["Alarm Delay", "", "mdi:alarm", None], - "ambtemp": ["Ambient Temperature", "", "mdi:thermometer", None], - "apc": ["Status Data", "", "mdi:information-outline", None], - "apcmodel": ["Model", "", "mdi:information-outline", None], - "badbatts": ["Bad Batteries", "", "mdi:information-outline", None], - "battdate": ["Battery Replaced", "", "mdi:calendar-clock", None], - "battstat": ["Battery Status", "", "mdi:information-outline", None], + "alarmdel": ["Alarm Delay", None, "mdi:alarm", None], + "ambtemp": ["Ambient Temperature", None, "mdi:thermometer", None], + "apc": ["Status Data", None, "mdi:information-outline", None], + "apcmodel": ["Model", None, "mdi:information-outline", None], + "badbatts": ["Bad Batteries", None, "mdi:information-outline", None], + "battdate": ["Battery Replaced", None, "mdi:calendar-clock", None], + "battstat": ["Battery Status", None, "mdi:information-outline", None], "battv": ["Battery Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], "bcharge": ["Battery", PERCENTAGE, "mdi:battery", None], - "cable": ["Cable Type", "", "mdi:ethernet-cable", None], - "cumonbatt": ["Total Time on Battery", "", "mdi:timer-outline", None], - "date": ["Status Date", "", "mdi:calendar-clock", None], - "dipsw": ["Dip Switch Settings", "", "mdi:information-outline", None], - "dlowbatt": ["Low Battery Signal", "", "mdi:clock-alert", None], - "driver": ["Driver", "", "mdi:information-outline", None], - "dshutd": ["Shutdown Delay", "", "mdi:timer-outline", None], - "dwake": ["Wake Delay", "", "mdi:timer-outline", None], - "endapc": ["Date and Time", "", "mdi:calendar-clock", None], - "extbatts": ["External Batteries", "", "mdi:information-outline", None], - "firmware": ["Firmware Version", "", "mdi:information-outline", None], + "cable": ["Cable Type", None, "mdi:ethernet-cable", None], + "cumonbatt": ["Total Time on Battery", None, "mdi:timer-outline", None], + "date": ["Status Date", None, "mdi:calendar-clock", None], + "dipsw": ["Dip Switch Settings", None, "mdi:information-outline", None], + "dlowbatt": ["Low Battery Signal", None, "mdi:clock-alert", None], + "driver": ["Driver", None, "mdi:information-outline", None], + "dshutd": ["Shutdown Delay", None, "mdi:timer-outline", None], + "dwake": ["Wake Delay", None, "mdi:timer-outline", None], + "endapc": ["Date and Time", None, "mdi:calendar-clock", None], + "extbatts": ["External Batteries", None, "mdi:information-outline", None], + "firmware": ["Firmware Version", None, "mdi:information-outline", None], "hitrans": ["Transfer High", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], - "hostname": ["Hostname", "", "mdi:information-outline", None], + "hostname": ["Hostname", None, "mdi:information-outline", None], "humidity": ["Ambient Humidity", PERCENTAGE, "mdi:water-percent", None], "itemp": ["Internal Temperature", TEMP_CELSIUS, None, DEVICE_CLASS_TEMPERATURE], - "lastxfer": ["Last Transfer", "", "mdi:transfer", None], - "linefail": ["Input Voltage Status", "", "mdi:information-outline", None], + "lastxfer": ["Last Transfer", None, "mdi:transfer", None], + "linefail": ["Input Voltage Status", None, "mdi:information-outline", None], "linefreq": ["Line Frequency", FREQUENCY_HERTZ, "mdi:information-outline", None], "linev": ["Input Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], "loadpct": ["Load", PERCENTAGE, "mdi:gauge", None], "loadapnt": ["Load Apparent Power", PERCENTAGE, "mdi:gauge", None], "lotrans": ["Transfer Low", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], - "mandate": ["Manufacture Date", "", "mdi:calendar", None], - "masterupd": ["Master Update", "", "mdi:information-outline", None], + "mandate": ["Manufacture Date", None, "mdi:calendar", None], + "masterupd": ["Master Update", None, "mdi:information-outline", None], "maxlinev": ["Input Voltage High", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], - "maxtime": ["Battery Timeout", "", "mdi:timer-off-outline", None], + "maxtime": ["Battery Timeout", None, "mdi:timer-off-outline", None], "mbattchg": ["Battery Shutdown", PERCENTAGE, "mdi:battery-alert", None], "minlinev": ["Input Voltage Low", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], - "mintimel": ["Shutdown Time", "", "mdi:timer-outline", None], - "model": ["Model", "", "mdi:information-outline", None], + "mintimel": ["Shutdown Time", None, "mdi:timer-outline", None], + "model": ["Model", None, "mdi:information-outline", None], "nombattv": ["Battery Nominal Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], "nominv": ["Nominal Input Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], "nomoutv": ["Nominal Output Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], "nompower": ["Nominal Output Power", POWER_WATT, "mdi:flash", None], "nomapnt": ["Nominal Apparent Power", POWER_VOLT_AMPERE, "mdi:flash", None], - "numxfers": ["Transfer Count", "", "mdi:counter", None], + "numxfers": ["Transfer Count", None, "mdi:counter", None], "outcurnt": ["Output Current", ELECTRIC_CURRENT_AMPERE, "mdi:flash", None], "outputv": ["Output Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None], - "reg1": ["Register 1 Fault", "", "mdi:information-outline", None], - "reg2": ["Register 2 Fault", "", "mdi:information-outline", None], - "reg3": ["Register 3 Fault", "", "mdi:information-outline", None], + "reg1": ["Register 1 Fault", None, "mdi:information-outline", None], + "reg2": ["Register 2 Fault", None, "mdi:information-outline", None], + "reg3": ["Register 3 Fault", None, "mdi:information-outline", None], "retpct": ["Restore Requirement", PERCENTAGE, "mdi:battery-alert", None], - "selftest": ["Last Self Test", "", "mdi:calendar-clock", None], - "sense": ["Sensitivity", "", "mdi:information-outline", None], - "serialno": ["Serial Number", "", "mdi:information-outline", None], - "starttime": ["Startup Time", "", "mdi:calendar-clock", None], - "statflag": ["Status Flag", "", "mdi:information-outline", None], - "status": ["Status", "", "mdi:information-outline", None], - "stesti": ["Self Test Interval", "", "mdi:information-outline", None], - "timeleft": ["Time Left", "", "mdi:clock-alert", None], - "tonbatt": ["Time on Battery", "", "mdi:timer-outline", None], - "upsmode": ["Mode", "", "mdi:information-outline", None], - "upsname": ["Name", "", "mdi:information-outline", None], - "version": ["Daemon Info", "", "mdi:information-outline", None], - "xoffbat": ["Transfer from Battery", "", "mdi:transfer", None], - "xoffbatt": ["Transfer from Battery", "", "mdi:transfer", None], - "xonbatt": ["Transfer to Battery", "", "mdi:transfer", None], + "selftest": ["Last Self Test", None, "mdi:calendar-clock", None], + "sense": ["Sensitivity", None, "mdi:information-outline", None], + "serialno": ["Serial Number", None, "mdi:information-outline", None], + "starttime": ["Startup Time", None, "mdi:calendar-clock", None], + "statflag": ["Status Flag", None, "mdi:information-outline", None], + "status": ["Status", None, "mdi:information-outline", None], + "stesti": ["Self Test Interval", None, "mdi:information-outline", None], + "timeleft": ["Time Left", None, "mdi:clock-alert", None], + "tonbatt": ["Time on Battery", None, "mdi:timer-outline", None], + "upsmode": ["Mode", None, "mdi:information-outline", None], + "upsname": ["Name", None, "mdi:information-outline", None], + "version": ["Daemon Info", None, "mdi:information-outline", None], + "xoffbat": ["Transfer from Battery", None, "mdi:transfer", None], + "xoffbatt": ["Transfer from Battery", None, "mdi:transfer", None], + "xonbatt": ["Transfer to Battery", None, "mdi:transfer", None], } SPECIFIC_UNITS = {"ITEMP": TEMP_CELSIUS} @@ -165,8 +165,7 @@ class APCUPSdSensor(SensorEntity): self.type = sensor_type self._attr_name = SENSOR_PREFIX + SENSOR_TYPES[sensor_type][0] self._attr_icon = SENSOR_TYPES[self.type][2] - if SENSOR_TYPES[sensor_type][1]: - self._attr_unit_of_measurement = SENSOR_TYPES[sensor_type][1] + self._attr_unit_of_measurement = SENSOR_TYPES[sensor_type][1] self._attr_device_class = SENSOR_TYPES[sensor_type][3] def update(self): diff --git a/homeassistant/components/fritz/sensor.py b/homeassistant/components/fritz/sensor.py index 482d5b1d688..faf2be23164 100644 --- a/homeassistant/components/fritz/sensor.py +++ b/homeassistant/components/fritz/sensor.py @@ -61,32 +61,32 @@ def _retrieve_external_ip_state(status: FritzStatus, last_value: str) -> str: def _retrieve_kb_s_sent_state(status: FritzStatus, last_value: str) -> float: """Return upload transmission rate.""" - return round(status.transmission_rate[0] / 1024, 1) # type: ignore[no-any-return] + return round(status.transmission_rate[0] / 1000, 1) # type: ignore[no-any-return] def _retrieve_kb_s_received_state(status: FritzStatus, last_value: str) -> float: """Return download transmission rate.""" - return round(status.transmission_rate[1] / 1024, 1) # type: ignore[no-any-return] + return round(status.transmission_rate[1] / 1000, 1) # type: ignore[no-any-return] def _retrieve_max_kb_s_sent_state(status: FritzStatus, last_value: str) -> float: """Return upload max transmission rate.""" - return round(status.max_bit_rate[0] / 1024, 1) # type: ignore[no-any-return] + return round(status.max_bit_rate[0] / 1000, 1) # type: ignore[no-any-return] def _retrieve_max_kb_s_received_state(status: FritzStatus, last_value: str) -> float: """Return download max transmission rate.""" - return round(status.max_bit_rate[1] / 1024, 1) # type: ignore[no-any-return] + return round(status.max_bit_rate[1] / 1000, 1) # type: ignore[no-any-return] def _retrieve_gb_sent_state(status: FritzStatus, last_value: str) -> float: """Return upload total data.""" - return round(status.bytes_sent * 8 / 1024 / 1024 / 1024, 1) # type: ignore[no-any-return] + return round(status.bytes_sent * 8 / 1000 / 1000 / 1000, 1) # type: ignore[no-any-return] def _retrieve_gb_received_state(status: FritzStatus, last_value: str) -> float: """Return download total data.""" - return round(status.bytes_received * 8 / 1024 / 1024 / 1024, 1) # type: ignore[no-any-return] + return round(status.bytes_received * 8 / 1000 / 1000 / 1000, 1) # type: ignore[no-any-return] class SensorData(TypedDict, total=False): diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index fbf676687cb..b9a84cbec02 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -2,9 +2,7 @@ "domain": "frontend", "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", - "requirements": [ - "home-assistant-frontend==20210803.2" - ], + "requirements": ["home-assistant-frontend==20210804.0"], "dependencies": [ "api", "auth", @@ -17,8 +15,6 @@ "system_log", "websocket_api" ], - "codeowners": [ - "@home-assistant/frontend" - ], + "codeowners": ["@home-assistant/frontend"], "quality_scale": "internal" -} \ No newline at end of file +} diff --git a/homeassistant/components/modbus/base_platform.py b/homeassistant/components/modbus/base_platform.py index b321183fd66..5b3cdfb48ee 100644 --- a/homeassistant/components/modbus/base_platform.py +++ b/homeassistant/components/modbus/base_platform.py @@ -60,7 +60,11 @@ class BasePlatform(Entity): def __init__(self, hub: ModbusHub, entry: dict[str, Any]) -> None: """Initialize the Modbus binary sensor.""" self._hub = hub - self._slave = entry.get(CONF_SLAVE) + # temporary fix, + # make sure slave is always defined to avoid an error in pymodbus + # attr(in_waiting) not defined. + # see issue #657 and PR #660 in riptideio/pymodbus + self._slave = entry.get(CONF_SLAVE, 0) self._address = int(entry[CONF_ADDRESS]) self._input_type = entry[CONF_INPUT_TYPE] self._value = None diff --git a/homeassistant/components/panasonic_viera/__init__.py b/homeassistant/components/panasonic_viera/__init__.py index b217be4d4b6..e187b7c18a5 100644 --- a/homeassistant/components/panasonic_viera/__init__.py +++ b/homeassistant/components/panasonic_viera/__init__.py @@ -1,7 +1,7 @@ """The Panasonic Viera integration.""" from functools import partial import logging -from urllib.request import URLError +from urllib.request import HTTPError, URLError from panasonic_viera import EncryptionRequired, Keys, RemoteControl, SOAPError import voluptuous as vol @@ -247,11 +247,13 @@ class Remote: "The connection couldn't be encrypted. Please reconfigure your TV" ) self.available = False - except (SOAPError): + except (SOAPError, HTTPError) as err: + _LOGGER.debug("An error occurred: %s", err) self.state = STATE_OFF self.available = True await self.async_create_remote_control() - except (URLError, OSError): + except (URLError, OSError) as err: + _LOGGER.debug("An error occurred: %s", err) self.state = STATE_OFF self.available = self._on_action is not None await self.async_create_remote_control() diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index 2ebef334873..434717f7a85 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -654,7 +654,11 @@ class SonosSpeaker: @callback def _async_regroup(group: list[str]) -> None: """Rebuild internal group layout.""" - if group == [self.soco.uid] and self.sonos_group == [self]: + if ( + group == [self.soco.uid] + and self.sonos_group == [self] + and self.sonos_group_entities + ): # Skip updating existing single speakers in polling mode return diff --git a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py index f450895f5c3..ae5596ee2e1 100644 --- a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py +++ b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py @@ -86,11 +86,12 @@ async def async_setup_entry( class YaleAlarmDevice(CoordinatorEntity, AlarmControlPanelEntity): """Represent a Yale Smart Alarm.""" - coordinator: YaleDataUpdateCoordinator - - _attr_name: str = coordinator.entry.data[CONF_NAME] - _attr_unique_id: str = coordinator.entry.entry_id - _identifier: str = coordinator.entry.data[CONF_USERNAME] + def __init__(self, coordinator: YaleDataUpdateCoordinator) -> None: + """Initialize the Yale Alarm Device.""" + super().__init__(coordinator) + self._attr_name: str = coordinator.entry.data[CONF_NAME] + self._attr_unique_id = coordinator.entry.entry_id + self._identifier: str = coordinator.entry.data[CONF_USERNAME] @property def device_info(self) -> DeviceInfo: diff --git a/homeassistant/const.py b/homeassistant/const.py index b95825ae39e..65ae1a569c3 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -5,7 +5,7 @@ from typing import Final MAJOR_VERSION: Final = 2021 MINOR_VERSION: Final = 8 -PATCH_VERSION: Final = "0" +PATCH_VERSION: Final = "1" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 7b9fe917279..cc4bb9d72ac 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -17,7 +17,7 @@ defusedxml==0.7.1 distro==1.5.0 emoji==1.2.0 hass-nabucasa==0.44.0 -home-assistant-frontend==20210803.2 +home-assistant-frontend==20210804.0 httpx==0.18.2 ifaddr==0.1.7 jinja2==3.0.1 diff --git a/requirements_all.txt b/requirements_all.txt index f15f5cf66ee..11fa22976fd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -783,7 +783,7 @@ hole==0.5.1 holidays==0.11.2 # homeassistant.components.frontend -home-assistant-frontend==20210803.2 +home-assistant-frontend==20210804.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 29a8352f433..fea89dc8b57 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -449,7 +449,7 @@ hole==0.5.1 holidays==0.11.2 # homeassistant.components.frontend -home-assistant-frontend==20210803.2 +home-assistant-frontend==20210804.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 diff --git a/tests/components/panasonic_viera/conftest.py b/tests/components/panasonic_viera/conftest.py index d1444f01477..e30c0f41e92 100644 --- a/tests/components/panasonic_viera/conftest.py +++ b/tests/components/panasonic_viera/conftest.py @@ -17,8 +17,12 @@ from homeassistant.components.panasonic_viera.const import ( DEFAULT_MODEL_NUMBER, DEFAULT_NAME, DEFAULT_PORT, + DOMAIN, ) from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry MOCK_BASIC_DATA = { CONF_HOST: "0.0.0.0", @@ -74,20 +78,11 @@ def get_mock_remote( mock_remote.authorize_pin_code = authorize_pin_code - def get_device_info(): - return device_info + mock_remote.get_device_info = Mock(return_value=device_info) - mock_remote.get_device_info = get_device_info + mock_remote.send_key = Mock() - def send_key(key): - return - - mock_remote.send_key = Mock(send_key) - - def get_volume(key): - return 100 - - mock_remote.get_volume = Mock(get_volume) + mock_remote.get_volume = Mock(return_value=100) return mock_remote @@ -102,3 +97,21 @@ def mock_remote_fixture(): return_value=mock_remote, ): yield mock_remote + + +@pytest.fixture +async def init_integration(hass: HomeAssistant, mock_remote: Mock) -> MockConfigEntry: + """Set up the Panasonic Viera integration for testing.""" + + mock_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=MOCK_DEVICE_INFO[ATTR_UDN], + data={**MOCK_CONFIG_DATA, **MOCK_ENCRYPTION_DATA, **MOCK_DEVICE_INFO}, + ) + + mock_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() + + return mock_entry diff --git a/tests/components/panasonic_viera/test_media_player.py b/tests/components/panasonic_viera/test_media_player.py new file mode 100644 index 00000000000..1203bf1ed51 --- /dev/null +++ b/tests/components/panasonic_viera/test_media_player.py @@ -0,0 +1,47 @@ +"""Test the Panasonic Viera media player entity.""" + +from datetime import timedelta +from unittest.mock import Mock +from urllib.error import HTTPError, URLError + +from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE +from homeassistant.core import HomeAssistant +from homeassistant.util.dt import utcnow + +from tests.common import MockConfigEntry, async_fire_time_changed + + +async def test_media_player_handle_URLerror( + hass: HomeAssistant, init_integration: MockConfigEntry, mock_remote: Mock +) -> None: + """Test remote handle URLError as Unavailable.""" + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv.state == STATE_ON + + # simulate timeout error + mock_remote.get_mute = Mock(side_effect=URLError(None, None)) + + async_fire_time_changed(hass, utcnow() + timedelta(minutes=2)) + await hass.async_block_till_done() + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv.state == STATE_UNAVAILABLE + + +async def test_media_player_handle_HTTPError( + hass: HomeAssistant, init_integration: MockConfigEntry, mock_remote: Mock +) -> None: + """Test remote handle HTTPError as Off.""" + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv.state == STATE_ON + + # simulate http badrequest + mock_remote.get_mute = Mock(side_effect=HTTPError(None, 400, None, None, None)) + + async_fire_time_changed(hass, utcnow() + timedelta(minutes=2)) + await hass.async_block_till_done() + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv.state == STATE_OFF diff --git a/tests/components/panasonic_viera/test_remote.py b/tests/components/panasonic_viera/test_remote.py index 6bfd7dee8eb..0cf80853351 100644 --- a/tests/components/panasonic_viera/test_remote.py +++ b/tests/components/panasonic_viera/test_remote.py @@ -1,8 +1,8 @@ """Test the Panasonic Viera remote entity.""" -from unittest.mock import call +from unittest.mock import Mock, call -from panasonic_viera import Keys +from panasonic_viera import Keys, SOAPError from homeassistant.components.panasonic_viera.const import ATTR_UDN, DOMAIN from homeassistant.components.remote import ( @@ -38,6 +38,9 @@ async def test_onoff(hass, mock_remote): data = {ATTR_ENTITY_ID: "remote.panasonic_viera_tv"} + # simulate tv off when async_update + mock_remote.get_mute = Mock(side_effect=SOAPError) + await hass.services.async_call(REMOTE_DOMAIN, SERVICE_TURN_OFF, data) await hass.services.async_call(REMOTE_DOMAIN, SERVICE_TURN_ON, data) await hass.async_block_till_done()