mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 16:17:20 +00:00
2022.12.4 (#83870)
This commit is contained in:
commit
05c429bcd7
@ -7,9 +7,9 @@
|
|||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"bleak==0.19.2",
|
"bleak==0.19.2",
|
||||||
"bleak-retry-connector==2.10.1",
|
"bleak-retry-connector==2.10.2",
|
||||||
"bluetooth-adapters==0.12.0",
|
"bluetooth-adapters==0.12.0",
|
||||||
"bluetooth-auto-recovery==0.5.5",
|
"bluetooth-auto-recovery==1.0.0",
|
||||||
"bluetooth-data-tools==0.3.0",
|
"bluetooth-data-tools==0.3.0",
|
||||||
"dbus-fast==1.75.0"
|
"dbus-fast==1.75.0"
|
||||||
],
|
],
|
||||||
|
@ -130,6 +130,7 @@ class HaScanner(BaseHaScanner):
|
|||||||
new_info_callback: Callable[[BluetoothServiceInfoBleak], None],
|
new_info_callback: Callable[[BluetoothServiceInfoBleak], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init bluetooth discovery."""
|
"""Init bluetooth discovery."""
|
||||||
|
self.mac_address = address
|
||||||
source = address if address != DEFAULT_ADDRESS else adapter or SOURCE_LOCAL
|
source = address if address != DEFAULT_ADDRESS else adapter or SOURCE_LOCAL
|
||||||
super().__init__(hass, source, adapter)
|
super().__init__(hass, source, adapter)
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@ -375,7 +376,7 @@ class HaScanner(BaseHaScanner):
|
|||||||
# so we log at debug level. If we later come up with a repair
|
# so we log at debug level. If we later come up with a repair
|
||||||
# strategy, we will change this to raise a repair issue as well.
|
# strategy, we will change this to raise a repair issue as well.
|
||||||
_LOGGER.debug("%s: adapter stopped responding; executing reset", self.name)
|
_LOGGER.debug("%s: adapter stopped responding; executing reset", self.name)
|
||||||
result = await async_reset_adapter(self.adapter)
|
result = await async_reset_adapter(self.adapter, self.mac_address)
|
||||||
_LOGGER.debug("%s: adapter reset result: %s", self.name, result)
|
_LOGGER.debug("%s: adapter reset result: %s", self.name, result)
|
||||||
|
|
||||||
async def async_stop(self) -> None:
|
async def async_stop(self) -> None:
|
||||||
|
@ -36,9 +36,9 @@ def async_load_history_from_system(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_reset_adapter(adapter: str | None) -> bool | None:
|
async def async_reset_adapter(adapter: str | None, mac_address: str) -> bool | None:
|
||||||
"""Reset the adapter."""
|
"""Reset the adapter."""
|
||||||
if adapter and adapter.startswith("hci"):
|
if adapter and adapter.startswith("hci"):
|
||||||
adapter_id = int(adapter[3:])
|
adapter_id = int(adapter[3:])
|
||||||
return await recover_adapter(adapter_id)
|
return await recover_adapter(adapter_id, mac_address)
|
||||||
return False
|
return False
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Google Cast",
|
"name": "Google Cast",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/cast",
|
"documentation": "https://www.home-assistant.io/integrations/cast",
|
||||||
"requirements": ["pychromecast==13.0.2"],
|
"requirements": ["pychromecast==13.0.3"],
|
||||||
"after_dependencies": [
|
"after_dependencies": [
|
||||||
"cloud",
|
"cloud",
|
||||||
"http",
|
"http",
|
||||||
|
@ -13,7 +13,7 @@ from homeassistant.data_entry_flow import FlowResult
|
|||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .subscription import async_subscription_info
|
from .subscription import async_migrate_paypal_agreement, async_subscription_info
|
||||||
|
|
||||||
BACKOFF_TIME = 5
|
BACKOFF_TIME = 5
|
||||||
MAX_RETRIES = 60 # This allows for 10 minutes of retries
|
MAX_RETRIES = 60 # This allows for 10 minutes of retries
|
||||||
@ -68,13 +68,13 @@ class LegacySubscriptionRepairFlow(RepairsFlow):
|
|||||||
async def async_step_change_plan(self, _: None = None) -> FlowResult:
|
async def async_step_change_plan(self, _: None = None) -> FlowResult:
|
||||||
"""Wait for the user to authorize the app installation."""
|
"""Wait for the user to authorize the app installation."""
|
||||||
|
|
||||||
|
cloud: Cloud = self.hass.data[DOMAIN]
|
||||||
|
|
||||||
async def _async_wait_for_plan_change() -> None:
|
async def _async_wait_for_plan_change() -> None:
|
||||||
flow_manager = repairs_flow_manager(self.hass)
|
flow_manager = repairs_flow_manager(self.hass)
|
||||||
# We can not get here without a flow manager
|
# We can not get here without a flow manager
|
||||||
assert flow_manager is not None
|
assert flow_manager is not None
|
||||||
|
|
||||||
cloud: Cloud = self.hass.data[DOMAIN]
|
|
||||||
|
|
||||||
retries = 0
|
retries = 0
|
||||||
while retries < MAX_RETRIES:
|
while retries < MAX_RETRIES:
|
||||||
self._data = await async_subscription_info(cloud)
|
self._data = await async_subscription_info(cloud)
|
||||||
@ -90,9 +90,10 @@ class LegacySubscriptionRepairFlow(RepairsFlow):
|
|||||||
|
|
||||||
if not self.wait_task:
|
if not self.wait_task:
|
||||||
self.wait_task = self.hass.async_create_task(_async_wait_for_plan_change())
|
self.wait_task = self.hass.async_create_task(_async_wait_for_plan_change())
|
||||||
|
migration = await async_migrate_paypal_agreement(cloud)
|
||||||
return self.async_external_step(
|
return self.async_external_step(
|
||||||
step_id="change_plan",
|
step_id="change_plan",
|
||||||
url="https://account.nabucasa.com/",
|
url=migration["url"] if migration else "https://account.nabucasa.com/",
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.wait_task
|
await self.wait_task
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Subscription information."""
|
"""Subscription information."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -18,7 +19,28 @@ async def async_subscription_info(cloud: Cloud) -> dict[str, Any] | None:
|
|||||||
try:
|
try:
|
||||||
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
||||||
return await cloud_api.async_subscription_info(cloud)
|
return await cloud_api.async_subscription_info(cloud)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error(
|
||||||
|
"A timeout of %s was reached while trying to fetch subscription information",
|
||||||
|
REQUEST_TIMEOUT,
|
||||||
|
)
|
||||||
except ClientError:
|
except ClientError:
|
||||||
_LOGGER.error("Failed to fetch subscription information")
|
_LOGGER.error("Failed to fetch subscription information")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_paypal_agreement(cloud: Cloud) -> dict[str, Any] | None:
|
||||||
|
"""Migrate a paypal agreement from legacy."""
|
||||||
|
try:
|
||||||
|
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
||||||
|
return await cloud_api.async_migrate_paypal_agreement(cloud)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error(
|
||||||
|
"A timeout of %s was reached while trying to start agreement migration",
|
||||||
|
REQUEST_TIMEOUT,
|
||||||
|
)
|
||||||
|
except ClientError as exception:
|
||||||
|
_LOGGER.error("Failed to start agreement migration - %s", exception)
|
||||||
|
|
||||||
|
return None
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from xml.etree.ElementTree import ParseError
|
||||||
|
|
||||||
from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError
|
from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError
|
||||||
from pyfritzhome.devicetypes.fritzhomeentitybase import FritzhomeEntityBase
|
from pyfritzhome.devicetypes.fritzhomeentitybase import FritzhomeEntityBase
|
||||||
@ -43,7 +44,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
CONF_CONNECTIONS: fritz,
|
CONF_CONNECTIONS: fritz,
|
||||||
}
|
}
|
||||||
|
|
||||||
coordinator = FritzboxDataUpdateCoordinator(hass, entry)
|
try:
|
||||||
|
await hass.async_add_executor_job(fritz.update_templates)
|
||||||
|
except ParseError:
|
||||||
|
LOGGER.debug("Disable smarthome templates")
|
||||||
|
has_templates = False
|
||||||
|
else:
|
||||||
|
LOGGER.debug("Enable smarthome templates")
|
||||||
|
has_templates = True
|
||||||
|
|
||||||
|
coordinator = FritzboxDataUpdateCoordinator(hass, entry, has_templates)
|
||||||
|
|
||||||
await coordinator.async_config_entry_first_refresh()
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from xml.etree.ElementTree import ParseError
|
|
||||||
|
|
||||||
from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError
|
from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError
|
||||||
from pyfritzhome.devicetypes import FritzhomeTemplate
|
from pyfritzhome.devicetypes import FritzhomeTemplate
|
||||||
@ -30,17 +29,14 @@ class FritzboxDataUpdateCoordinator(DataUpdateCoordinator[FritzboxCoordinatorDat
|
|||||||
|
|
||||||
configuration_url: str
|
configuration_url: str
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
|
def __init__(
|
||||||
|
self, hass: HomeAssistant, entry: ConfigEntry, has_templates: bool
|
||||||
|
) -> None:
|
||||||
"""Initialize the Fritzbox Smarthome device coordinator."""
|
"""Initialize the Fritzbox Smarthome device coordinator."""
|
||||||
self.entry = entry
|
self.entry = entry
|
||||||
self.fritz: Fritzhome = hass.data[DOMAIN][self.entry.entry_id][CONF_CONNECTIONS]
|
self.fritz: Fritzhome = hass.data[DOMAIN][self.entry.entry_id][CONF_CONNECTIONS]
|
||||||
self.configuration_url = self.fritz.get_prefixed_host()
|
self.configuration_url = self.fritz.get_prefixed_host()
|
||||||
self.has_templates = True
|
self.has_templates = has_templates
|
||||||
try:
|
|
||||||
hass.async_add_executor_job(self.fritz.update_templates)
|
|
||||||
except ParseError:
|
|
||||||
LOGGER.info("Disable smarthome templates")
|
|
||||||
self.has_templates = False
|
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"domain": "frontend",
|
"domain": "frontend",
|
||||||
"name": "Home Assistant Frontend",
|
"name": "Home Assistant Frontend",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||||
"requirements": ["home-assistant-frontend==20221208.0"],
|
"requirements": ["home-assistant-frontend==20221212.0"],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"api",
|
"api",
|
||||||
"auth",
|
"auth",
|
||||||
|
@ -18,7 +18,7 @@ from homeassistant.const import (
|
|||||||
SERVICE_TURN_ON,
|
SERVICE_TURN_ON,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import State, callback
|
||||||
|
|
||||||
from .accessories import TYPES, HomeAccessory
|
from .accessories import TYPES, HomeAccessory
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -96,7 +96,7 @@ class RemoteInputSelectAccessory(HomeAccessory):
|
|||||||
self.sources = []
|
self.sources = []
|
||||||
self.support_select_source = False
|
self.support_select_source = False
|
||||||
if features & required_feature:
|
if features & required_feature:
|
||||||
sources = state.attributes.get(source_list_key, [])
|
sources = self._get_ordered_source_list_from_state(state)
|
||||||
if len(sources) > MAXIMUM_SOURCES:
|
if len(sources) > MAXIMUM_SOURCES:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"%s: Reached maximum number of sources (%s)",
|
"%s: Reached maximum number of sources (%s)",
|
||||||
@ -143,6 +143,21 @@ class RemoteInputSelectAccessory(HomeAccessory):
|
|||||||
serv_input.configure_char(CHAR_CURRENT_VISIBILITY_STATE, value=False)
|
serv_input.configure_char(CHAR_CURRENT_VISIBILITY_STATE, value=False)
|
||||||
_LOGGER.debug("%s: Added source %s", self.entity_id, source)
|
_LOGGER.debug("%s: Added source %s", self.entity_id, source)
|
||||||
|
|
||||||
|
def _get_ordered_source_list_from_state(self, state: State) -> list[str]:
|
||||||
|
"""Return ordered source list while preserving order with duplicates removed.
|
||||||
|
|
||||||
|
Some integrations have duplicate sources in the source list
|
||||||
|
which will make the source list conflict as HomeKit requires
|
||||||
|
unique source names.
|
||||||
|
"""
|
||||||
|
seen = set()
|
||||||
|
sources: list[str] = []
|
||||||
|
for source in state.attributes.get(self.source_list_key, []):
|
||||||
|
if source not in seen:
|
||||||
|
sources.append(source)
|
||||||
|
seen.add(source)
|
||||||
|
return sources
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set_on_off(self, value):
|
def set_on_off(self, value):
|
||||||
"""Move switch state to value if call came from HomeKit."""
|
"""Move switch state to value if call came from HomeKit."""
|
||||||
@ -169,7 +184,7 @@ class RemoteInputSelectAccessory(HomeAccessory):
|
|||||||
self.char_input_source.set_value(index)
|
self.char_input_source.set_value(index)
|
||||||
return
|
return
|
||||||
|
|
||||||
possible_sources = new_state.attributes.get(self.source_list_key, [])
|
possible_sources = self._get_ordered_source_list_from_state(new_state)
|
||||||
if source in possible_sources:
|
if source in possible_sources:
|
||||||
index = possible_sources.index(source)
|
index = possible_sources.index(source)
|
||||||
if index >= MAXIMUM_SOURCES:
|
if index >= MAXIMUM_SOURCES:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/overkiz",
|
"documentation": "https://www.home-assistant.io/integrations/overkiz",
|
||||||
"requirements": ["pyoverkiz==1.7.1"],
|
"requirements": ["pyoverkiz==1.7.2"],
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
{
|
{
|
||||||
"type": "_kizbox._tcp.local.",
|
"type": "_kizbox._tcp.local.",
|
||||||
|
@ -305,14 +305,6 @@ class DomesticHotWaterProduction(OverkizEntity, WaterHeaterEntity):
|
|||||||
OverkizCommand.SET_BOOST_MODE, OverkizCommand.OFF
|
OverkizCommand.SET_BOOST_MODE, OverkizCommand.OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.executor.has_command(OverkizCommand.SET_BOOST_MODE_DURATION):
|
|
||||||
await self.executor.async_execute_command(
|
|
||||||
OverkizCommand.SET_BOOST_MODE_DURATION, 0
|
|
||||||
)
|
|
||||||
await self.executor.async_execute_command(
|
|
||||||
OverkizCommand.REFRESH_BOOST_MODE_DURATION
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.executor.has_command(OverkizCommand.SET_CURRENT_OPERATING_MODE):
|
if self.executor.has_command(OverkizCommand.SET_CURRENT_OPERATING_MODE):
|
||||||
current_operating_mode = self.executor.select_state(
|
current_operating_mode = self.executor.select_state(
|
||||||
OverkizState.CORE_OPERATING_MODE
|
OverkizState.CORE_OPERATING_MODE
|
||||||
@ -331,5 +323,10 @@ class DomesticHotWaterProduction(OverkizEntity, WaterHeaterEntity):
|
|||||||
OverkizCommand.SET_DHW_MODE, self.overkiz_to_operation_mode[operation_mode]
|
OverkizCommand.SET_DHW_MODE, self.overkiz_to_operation_mode[operation_mode]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.executor.has_command(OverkizCommand.REFRESH_BOOST_MODE_DURATION):
|
||||||
|
await self.executor.async_execute_command(
|
||||||
|
OverkizCommand.REFRESH_BOOST_MODE_DURATION
|
||||||
|
)
|
||||||
|
|
||||||
if self.executor.has_command(OverkizCommand.REFRESH_DHW_MODE):
|
if self.executor.has_command(OverkizCommand.REFRESH_DHW_MODE):
|
||||||
await self.executor.async_execute_command(OverkizCommand.REFRESH_DHW_MODE)
|
await self.executor.async_execute_command(OverkizCommand.REFRESH_DHW_MODE)
|
||||||
|
@ -85,7 +85,7 @@ class SleepIQFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
self._reauth_entry = self.hass.config_entries.async_get_entry(
|
self._reauth_entry = self.hass.config_entries.async_get_entry(
|
||||||
self.context["entry_id"]
|
self.context["entry_id"]
|
||||||
)
|
)
|
||||||
return await self.async_step_reauth_confirm(dict(entry_data))
|
return await self.async_step_reauth_confirm()
|
||||||
|
|
||||||
async def async_step_reauth_confirm(
|
async def async_step_reauth_confirm(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"bellows==0.34.5",
|
"bellows==0.34.5",
|
||||||
"pyserial==3.5",
|
"pyserial==3.5",
|
||||||
"pyserial-asyncio==0.6",
|
"pyserial-asyncio==0.6",
|
||||||
"zha-quirks==0.0.88",
|
"zha-quirks==0.0.89",
|
||||||
"zigpy-deconz==0.19.2",
|
"zigpy-deconz==0.19.2",
|
||||||
"zigpy==0.52.3",
|
"zigpy==0.52.3",
|
||||||
"zigpy-xbee==0.16.2",
|
"zigpy-xbee==0.16.2",
|
||||||
|
@ -8,7 +8,7 @@ from .backports.enum import StrEnum
|
|||||||
APPLICATION_NAME: Final = "HomeAssistant"
|
APPLICATION_NAME: Final = "HomeAssistant"
|
||||||
MAJOR_VERSION: Final = 2022
|
MAJOR_VERSION: Final = 2022
|
||||||
MINOR_VERSION: Final = 12
|
MINOR_VERSION: Final = 12
|
||||||
PATCH_VERSION: Final = "3"
|
PATCH_VERSION: Final = "4"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
||||||
|
@ -10,10 +10,10 @@ atomicwrites-homeassistant==1.4.1
|
|||||||
attrs==21.2.0
|
attrs==21.2.0
|
||||||
awesomeversion==22.9.0
|
awesomeversion==22.9.0
|
||||||
bcrypt==3.1.7
|
bcrypt==3.1.7
|
||||||
bleak-retry-connector==2.10.1
|
bleak-retry-connector==2.10.2
|
||||||
bleak==0.19.2
|
bleak==0.19.2
|
||||||
bluetooth-adapters==0.12.0
|
bluetooth-adapters==0.12.0
|
||||||
bluetooth-auto-recovery==0.5.5
|
bluetooth-auto-recovery==1.0.0
|
||||||
bluetooth-data-tools==0.3.0
|
bluetooth-data-tools==0.3.0
|
||||||
certifi>=2021.5.30
|
certifi>=2021.5.30
|
||||||
ciso8601==2.2.0
|
ciso8601==2.2.0
|
||||||
@ -22,7 +22,7 @@ dbus-fast==1.75.0
|
|||||||
fnvhash==0.1.0
|
fnvhash==0.1.0
|
||||||
hass-nabucasa==0.61.0
|
hass-nabucasa==0.61.0
|
||||||
home-assistant-bluetooth==1.8.1
|
home-assistant-bluetooth==1.8.1
|
||||||
home-assistant-frontend==20221208.0
|
home-assistant-frontend==20221212.0
|
||||||
httpx==0.23.1
|
httpx==0.23.1
|
||||||
ifaddr==0.1.7
|
ifaddr==0.1.7
|
||||||
janus==1.0.0
|
janus==1.0.0
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "homeassistant"
|
name = "homeassistant"
|
||||||
version = "2022.12.3"
|
version = "2022.12.4"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "Open-source home automation platform running on Python 3."
|
description = "Open-source home automation platform running on Python 3."
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
|
@ -422,7 +422,7 @@ bimmer_connected==0.10.4
|
|||||||
bizkaibus==0.1.1
|
bizkaibus==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak-retry-connector==2.10.1
|
bleak-retry-connector==2.10.2
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak==0.19.2
|
bleak==0.19.2
|
||||||
@ -450,7 +450,7 @@ bluemaestro-ble==0.2.0
|
|||||||
bluetooth-adapters==0.12.0
|
bluetooth-adapters==0.12.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-auto-recovery==0.5.5
|
bluetooth-auto-recovery==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
# homeassistant.components.led_ble
|
# homeassistant.components.led_ble
|
||||||
@ -884,7 +884,7 @@ hole==0.7.0
|
|||||||
holidays==0.17.2
|
holidays==0.17.2
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20221208.0
|
home-assistant-frontend==20221212.0
|
||||||
|
|
||||||
# homeassistant.components.home_connect
|
# homeassistant.components.home_connect
|
||||||
homeconnect==0.7.2
|
homeconnect==0.7.2
|
||||||
@ -1504,7 +1504,7 @@ pycfdns==2.0.1
|
|||||||
pychannels==1.2.3
|
pychannels==1.2.3
|
||||||
|
|
||||||
# homeassistant.components.cast
|
# homeassistant.components.cast
|
||||||
pychromecast==13.0.2
|
pychromecast==13.0.3
|
||||||
|
|
||||||
# homeassistant.components.pocketcasts
|
# homeassistant.components.pocketcasts
|
||||||
pycketcasts==1.0.1
|
pycketcasts==1.0.1
|
||||||
@ -1812,7 +1812,7 @@ pyotgw==2.1.3
|
|||||||
pyotp==2.7.0
|
pyotp==2.7.0
|
||||||
|
|
||||||
# homeassistant.components.overkiz
|
# homeassistant.components.overkiz
|
||||||
pyoverkiz==1.7.1
|
pyoverkiz==1.7.2
|
||||||
|
|
||||||
# homeassistant.components.openweathermap
|
# homeassistant.components.openweathermap
|
||||||
pyowm==3.2.0
|
pyowm==3.2.0
|
||||||
@ -2639,7 +2639,7 @@ zengge==0.2
|
|||||||
zeroconf==0.39.4
|
zeroconf==0.39.4
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zha-quirks==0.0.88
|
zha-quirks==0.0.89
|
||||||
|
|
||||||
# homeassistant.components.zhong_hong
|
# homeassistant.components.zhong_hong
|
||||||
zhong_hong_hvac==1.0.9
|
zhong_hong_hvac==1.0.9
|
||||||
|
@ -346,7 +346,7 @@ bellows==0.34.5
|
|||||||
bimmer_connected==0.10.4
|
bimmer_connected==0.10.4
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak-retry-connector==2.10.1
|
bleak-retry-connector==2.10.2
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak==0.19.2
|
bleak==0.19.2
|
||||||
@ -364,7 +364,7 @@ bluemaestro-ble==0.2.0
|
|||||||
bluetooth-adapters==0.12.0
|
bluetooth-adapters==0.12.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bluetooth-auto-recovery==0.5.5
|
bluetooth-auto-recovery==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
# homeassistant.components.led_ble
|
# homeassistant.components.led_ble
|
||||||
@ -664,7 +664,7 @@ hole==0.7.0
|
|||||||
holidays==0.17.2
|
holidays==0.17.2
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20221208.0
|
home-assistant-frontend==20221212.0
|
||||||
|
|
||||||
# homeassistant.components.home_connect
|
# homeassistant.components.home_connect
|
||||||
homeconnect==0.7.2
|
homeconnect==0.7.2
|
||||||
@ -1077,7 +1077,7 @@ pybravia==0.2.3
|
|||||||
pycfdns==2.0.1
|
pycfdns==2.0.1
|
||||||
|
|
||||||
# homeassistant.components.cast
|
# homeassistant.components.cast
|
||||||
pychromecast==13.0.2
|
pychromecast==13.0.3
|
||||||
|
|
||||||
# homeassistant.components.comfoconnect
|
# homeassistant.components.comfoconnect
|
||||||
pycomfoconnect==0.4
|
pycomfoconnect==0.4
|
||||||
@ -1289,7 +1289,7 @@ pyotgw==2.1.3
|
|||||||
pyotp==2.7.0
|
pyotp==2.7.0
|
||||||
|
|
||||||
# homeassistant.components.overkiz
|
# homeassistant.components.overkiz
|
||||||
pyoverkiz==1.7.1
|
pyoverkiz==1.7.2
|
||||||
|
|
||||||
# homeassistant.components.openweathermap
|
# homeassistant.components.openweathermap
|
||||||
pyowm==3.2.0
|
pyowm==3.2.0
|
||||||
@ -1840,7 +1840,7 @@ zamg==0.1.1
|
|||||||
zeroconf==0.39.4
|
zeroconf==0.39.4
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zha-quirks==0.0.88
|
zha-quirks==0.0.89
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zigpy-deconz==0.19.2
|
zigpy-deconz==0.19.2
|
||||||
|
@ -88,6 +88,10 @@ async def test_legacy_subscription_repair_flow(
|
|||||||
"https://accounts.nabucasa.com/payments/subscription_info",
|
"https://accounts.nabucasa.com/payments/subscription_info",
|
||||||
json={"provider": None},
|
json={"provider": None},
|
||||||
)
|
)
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
json={"url": "https://paypal.com"},
|
||||||
|
)
|
||||||
|
|
||||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
||||||
repair_issue = issue_registry.async_get_issue(
|
repair_issue = issue_registry.async_get_issue(
|
||||||
@ -133,7 +137,7 @@ async def test_legacy_subscription_repair_flow(
|
|||||||
"flow_id": flow_id,
|
"flow_id": flow_id,
|
||||||
"handler": DOMAIN,
|
"handler": DOMAIN,
|
||||||
"step_id": "change_plan",
|
"step_id": "change_plan",
|
||||||
"url": "https://account.nabucasa.com/",
|
"url": "https://paypal.com",
|
||||||
"description_placeholders": None,
|
"description_placeholders": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +165,15 @@ async def test_legacy_subscription_repair_flow(
|
|||||||
async def test_legacy_subscription_repair_flow_timeout(
|
async def test_legacy_subscription_repair_flow_timeout(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: Callable[..., Awaitable[ClientSession]],
|
hass_client: Callable[..., Awaitable[ClientSession]],
|
||||||
|
mock_auth: Generator[None, AsyncMock, None],
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
):
|
):
|
||||||
"""Test timeout flow of the fix flow for legacy subscription."""
|
"""Test timeout flow of the fix flow for legacy subscription."""
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
status=403,
|
||||||
|
)
|
||||||
|
|
||||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||||
|
|
||||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
||||||
|
61
tests/components/cloud/test_subscription.py
Normal file
61
tests/components/cloud/test_subscription.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""Test cloud subscription functions."""
|
||||||
|
import asyncio
|
||||||
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
|
from hass_nabucasa import Cloud
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.cloud.subscription import (
|
||||||
|
async_migrate_paypal_agreement,
|
||||||
|
async_subscription_info,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="mocked_cloud")
|
||||||
|
def mocked_cloud_object(hass: HomeAssistant) -> Cloud:
|
||||||
|
"""Mock cloud object."""
|
||||||
|
return Mock(
|
||||||
|
accounts_server="accounts.nabucasa.com",
|
||||||
|
auth=Mock(async_check_token=AsyncMock()),
|
||||||
|
websession=async_get_clientsession(hass),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fetching_subscription_with_timeout_error(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
mocked_cloud: Cloud,
|
||||||
|
):
|
||||||
|
"""Test that we handle timeout error."""
|
||||||
|
aioclient_mock.get(
|
||||||
|
"https://accounts.nabucasa.com/payments/subscription_info",
|
||||||
|
exc=asyncio.TimeoutError(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert await async_subscription_info(mocked_cloud) is None
|
||||||
|
assert (
|
||||||
|
"A timeout of 10 was reached while trying to fetch subscription information"
|
||||||
|
in caplog.text
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migrate_paypal_agreement_with_timeout_error(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
mocked_cloud: Cloud,
|
||||||
|
):
|
||||||
|
"""Test that we handle timeout error."""
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
exc=asyncio.TimeoutError(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert await async_migrate_paypal_agreement(mocked_cloud) is None
|
||||||
|
assert (
|
||||||
|
"A timeout of 10 was reached while trying to start agreement migration"
|
||||||
|
in caplog.text
|
||||||
|
)
|
@ -512,3 +512,48 @@ async def test_media_player_television_max_sources(hass, hk_driver, events, capl
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert acc.char_input_source.value == 0
|
assert acc.char_input_source.value == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_media_player_television_duplicate_sources(
|
||||||
|
hass, hk_driver, events, caplog
|
||||||
|
):
|
||||||
|
"""Test if television accessory with duplicate sources."""
|
||||||
|
entity_id = "media_player.television"
|
||||||
|
sources = ["MUSIC", "HDMI", "SCREEN MIRRORING", "HDMI", "MUSIC"]
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_CLASS: MediaPlayerDeviceClass.TV,
|
||||||
|
ATTR_SUPPORTED_FEATURES: 3469,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED: False,
|
||||||
|
ATTR_INPUT_SOURCE: "HDMI",
|
||||||
|
ATTR_INPUT_SOURCE_LIST: sources,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = TelevisionMediaPlayer(hass, hk_driver, "MediaPlayer", entity_id, 2, None)
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert acc.aid == 2
|
||||||
|
assert acc.category == 31 # Television
|
||||||
|
|
||||||
|
assert acc.char_active.value == 0
|
||||||
|
assert acc.char_remote_key.value == 0
|
||||||
|
assert acc.char_input_source.value == 1
|
||||||
|
assert acc.char_mute.value is False
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_CLASS: MediaPlayerDeviceClass.TV,
|
||||||
|
ATTR_SUPPORTED_FEATURES: 3469,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED: False,
|
||||||
|
ATTR_INPUT_SOURCE: "MUSIC",
|
||||||
|
ATTR_INPUT_SOURCE_LIST: sources,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_input_source.value == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user