Merge pull request #73334 from home-assistant/rc

This commit is contained in:
Paulus Schoutsen 2022-06-10 14:01:57 -07:00 committed by GitHub
commit 3759adcf2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 218 additions and 125 deletions

View File

@ -70,6 +70,7 @@ class FeedManager:
self._last_entry_timestamp = None
self._last_update_successful = False
self._has_published_parsed = False
self._has_updated_parsed = False
self._event_type = EVENT_FEEDREADER
self._feed_id = url
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, lambda _: self._update())
@ -122,7 +123,7 @@ class FeedManager:
)
self._filter_entries()
self._publish_new_entries()
if self._has_published_parsed:
if self._has_published_parsed or self._has_updated_parsed:
self._storage.put_timestamp(
self._feed_id, self._last_entry_timestamp
)
@ -143,7 +144,7 @@ class FeedManager:
def _update_and_fire_entry(self, entry):
"""Update last_entry_timestamp and fire entry."""
# Check if the entry has a published date.
# Check if the entry has a published or updated date.
if "published_parsed" in entry and entry.published_parsed:
# We are lucky, `published_parsed` data available, let's make use of
# it to publish only new available entries since the last run
@ -151,9 +152,20 @@ class FeedManager:
self._last_entry_timestamp = max(
entry.published_parsed, self._last_entry_timestamp
)
elif "updated_parsed" in entry and entry.updated_parsed:
# We are lucky, `updated_parsed` data available, let's make use of
# it to publish only new available entries since the last run
self._has_updated_parsed = True
self._last_entry_timestamp = max(
entry.updated_parsed, self._last_entry_timestamp
)
else:
self._has_published_parsed = False
_LOGGER.debug("No published_parsed info available for entry %s", entry)
self._has_updated_parsed = False
_LOGGER.debug(
"No published_parsed or updated_parsed info available for entry %s",
entry,
)
entry.update({"feed_url": self._url})
self._hass.bus.fire(self._event_type, entry)
@ -167,9 +179,16 @@ class FeedManager:
# Set last entry timestamp as epoch time if not available
self._last_entry_timestamp = datetime.utcfromtimestamp(0).timetuple()
for entry in self._feed.entries:
if self._firstrun or (
if (
self._firstrun
or (
"published_parsed" in entry
and entry.published_parsed > self._last_entry_timestamp
)
or (
"updated_parsed" in entry
and entry.updated_parsed > self._last_entry_timestamp
)
):
self._update_and_fire_entry(entry)
new_entries = True

View File

@ -460,7 +460,7 @@ async def _async_setup_themes(
async def reload_themes(_: ServiceCall) -> None:
"""Reload themes."""
config = await async_hass_config_yaml(hass)
new_themes = config[DOMAIN].get(CONF_THEMES, {})
new_themes = config.get(DOMAIN, {}).get(CONF_THEMES, {})
hass.data[DATA_THEMES] = new_themes
if hass.data[DATA_DEFAULT_THEME] not in new_themes:
hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME

View File

@ -27,6 +27,7 @@ class HiveFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self.data = {}
self.tokens = {}
self.entry = None
self.device_registration = False
async def async_step_user(self, user_input=None):
"""Prompt user input. Create or edit entry."""
@ -88,6 +89,7 @@ class HiveFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if not errors:
try:
self.device_registration = True
return await self.async_setup_hive_entry()
except UnknownHiveError:
errors["base"] = "unknown"
@ -102,9 +104,10 @@ class HiveFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
raise UnknownHiveError
# Setup the config entry
if self.device_registration:
await self.hive_auth.device_registration("Home Assistant")
self.data["tokens"] = self.tokens
self.data["device_data"] = await self.hive_auth.getDeviceData()
self.data["tokens"] = self.tokens
if self.context["source"] == config_entries.SOURCE_REAUTH:
self.hass.config_entries.async_update_entry(
self.entry, title=self.data["username"], data=self.data

View File

@ -3,7 +3,7 @@
"name": "Hive",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/hive",
"requirements": ["pyhiveapi==0.5.5"],
"requirements": ["pyhiveapi==0.5.9"],
"codeowners": ["@Rendili", "@KJonline"],
"iot_class": "cloud_polling",
"loggers": ["apyhiveapi"]

View File

@ -28,7 +28,14 @@ from homeassistant.data_entry_flow import BaseServiceInfo
from homeassistant.exceptions import TemplateError, Unauthorized
from homeassistant.helpers import config_validation as cv, event, template
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.reload import (
async_integration_yaml_config,
async_setup_reload_service,
)
from homeassistant.helpers.typing import ConfigType
# Loading the config flow file will register the flow
@ -60,12 +67,14 @@ from .const import ( # noqa: F401
DATA_MQTT,
DATA_MQTT_CONFIG,
DATA_MQTT_RELOAD_NEEDED,
DATA_MQTT_UPDATED_CONFIG,
DEFAULT_ENCODING,
DEFAULT_QOS,
DEFAULT_RETAIN,
DOMAIN,
MQTT_CONNECTED,
MQTT_DISCONNECTED,
MQTT_RELOADED,
PLATFORMS,
)
from .models import ( # noqa: F401
@ -227,7 +236,9 @@ async def _async_config_entry_updated(hass: HomeAssistant, entry: ConfigEntry) -
await _async_setup_discovery(hass, mqtt_client.conf, entry)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry( # noqa: C901
hass: HomeAssistant, entry: ConfigEntry
) -> bool:
"""Load a config entry."""
# Merge basic configuration, and add missing defaults for basic options
_merge_basic_config(hass, entry, hass.data.get(DATA_MQTT_CONFIG, {}))
@ -364,6 +375,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
hass.data[CONFIG_ENTRY_IS_SETUP] = set()
# Setup reload service. Once support for legacy config is removed in 2022.9, we
# should no longer call async_setup_reload_service but instead implement a custom
# service
await async_setup_reload_service(hass, DOMAIN, PLATFORMS)
async def _async_reload_platforms(_: Event | None) -> None:
"""Discover entities for a platform."""
config_yaml = await async_integration_yaml_config(hass, DOMAIN) or {}
hass.data[DATA_MQTT_UPDATED_CONFIG] = config_yaml.get(DOMAIN, {})
async_dispatcher_send(hass, MQTT_RELOADED)
async def async_forward_entry_setup():
"""Forward the config entry setup to the platforms."""
async with hass.data[DATA_CONFIG_ENTRY_LOCK]:
@ -374,6 +396,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await hass.config_entries.async_forward_entry_setup(
entry, component
)
# Setup reload service after all platforms have loaded
entry.async_on_unload(
hass.bus.async_listen("event_mqtt_reloaded", _async_reload_platforms)
)
hass.async_create_task(async_forward_entry_setup())

View File

@ -35,6 +35,7 @@ DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock"
DATA_MQTT = "mqtt"
DATA_MQTT_CONFIG = "mqtt_config"
DATA_MQTT_RELOAD_NEEDED = "mqtt_reload_needed"
DATA_MQTT_UPDATED_CONFIG = "mqtt_updated_config"
DEFAULT_PREFIX = "homeassistant"
DEFAULT_BIRTH_WILL_TOPIC = DEFAULT_PREFIX + "/status"
@ -63,6 +64,7 @@ DOMAIN = "mqtt"
MQTT_CONNECTED = "mqtt_connected"
MQTT_DISCONNECTED = "mqtt_disconnected"
MQTT_RELOADED = "mqtt_reloaded"
PAYLOAD_EMPTY_JSON = "{}"
PAYLOAD_NONE = "None"

View File

@ -25,7 +25,6 @@ from homeassistant.const import (
STATE_CLOSING,
STATE_OPEN,
STATE_OPENING,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
@ -470,7 +469,6 @@ class MqttCover(MqttEntity, CoverEntity):
}
if self._config.get(CONF_TILT_STATUS_TOPIC) is not None:
self._tilt_value = STATE_UNKNOWN
topics["tilt_status_topic"] = {
"topic": self._config.get(CONF_TILT_STATUS_TOPIC),
"msg_callback": tilt_message_received,

View File

@ -48,10 +48,6 @@ from homeassistant.helpers.entity import (
async_generate_entity_id,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import (
async_integration_yaml_config,
async_setup_reload_service,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import debug_info, subscription
@ -67,13 +63,14 @@ from .const import (
DATA_MQTT,
DATA_MQTT_CONFIG,
DATA_MQTT_RELOAD_NEEDED,
DATA_MQTT_UPDATED_CONFIG,
DEFAULT_ENCODING,
DEFAULT_PAYLOAD_AVAILABLE,
DEFAULT_PAYLOAD_NOT_AVAILABLE,
DOMAIN,
MQTT_CONNECTED,
MQTT_DISCONNECTED,
PLATFORMS,
MQTT_RELOADED,
)
from .debug_info import log_message, log_messages
from .discovery import (
@ -270,14 +267,11 @@ async def async_setup_platform_discovery(
) -> CALLBACK_TYPE:
"""Set up platform discovery for manual config."""
async def _async_discover_entities(event: Event | None) -> None:
async def _async_discover_entities() -> None:
"""Discover entities for a platform."""
if event:
if DATA_MQTT_UPDATED_CONFIG in hass.data:
# The platform has been reloaded
config_yaml = await async_integration_yaml_config(hass, DOMAIN)
if not config_yaml:
return
config_yaml = config_yaml.get(DOMAIN, {})
config_yaml = hass.data[DATA_MQTT_UPDATED_CONFIG]
else:
config_yaml = hass.data.get(DATA_MQTT_CONFIG, {})
if not config_yaml:
@ -293,8 +287,8 @@ async def async_setup_platform_discovery(
)
)
unsub = hass.bus.async_listen("event_mqtt_reloaded", _async_discover_entities)
await _async_discover_entities(None)
unsub = async_dispatcher_connect(hass, MQTT_RELOADED, _async_discover_entities)
await _async_discover_entities()
return unsub
@ -359,7 +353,6 @@ async def async_setup_platform_helper(
async_setup_entities: SetupEntity,
) -> None:
"""Return true if platform setup should be aborted."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS)
if not bool(hass.config_entries.async_entries(DOMAIN)):
hass.data[DATA_MQTT_RELOAD_NEEDED] = None
_LOGGER.warning(

View File

@ -18,7 +18,6 @@ from .const import (
KEY_COORDINATOR_SPEED,
KEY_COORDINATOR_TRAFFIC,
KEY_ROUTER,
MODE_ROUTER,
PLATFORMS,
)
from .errors import CannotLoginException
@ -72,7 +71,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_update_devices() -> bool:
"""Fetch data from the router."""
if router.mode == MODE_ROUTER:
if router.track_devices:
return await router.async_update_device_trackers()
return False
@ -107,7 +106,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
update_interval=SPEED_TEST_INTERVAL,
)
if router.mode == MODE_ROUTER:
if router.track_devices:
await coordinator.async_config_entry_first_refresh()
await coordinator_traffic_meter.async_config_entry_first_refresh()
@ -134,7 +133,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
if router.mode != MODE_ROUTER:
if not router.track_devices:
router_id = None
# Remove devices that are no longer tracked
device_registry = dr.async_get(hass)

View File

@ -80,6 +80,7 @@ class NetgearRouter:
self.hardware_version = ""
self.serial_number = ""
self.track_devices = True
self.method_version = 1
consider_home_int = entry.options.get(
CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds()
@ -112,11 +113,23 @@ class NetgearRouter:
self.serial_number = self._info["SerialNumber"]
self.mode = self._info.get("DeviceMode", MODE_ROUTER)
enabled_entries = [
entry
for entry in self.hass.config_entries.async_entries(DOMAIN)
if entry.disabled_by is None
]
self.track_devices = self.mode == MODE_ROUTER or len(enabled_entries) == 1
_LOGGER.debug(
"Netgear track_devices = '%s', device mode '%s'",
self.track_devices,
self.mode,
)
for model in MODELS_V2:
if self.model.startswith(model):
self.method_version = 2
if self.method_version == 2 and self.mode == MODE_ROUTER:
if self.method_version == 2 and self.track_devices:
if not self._api.get_attached_devices_2():
_LOGGER.error(
"Netgear Model '%s' in MODELS_V2 list, but failed to get attached devices using V2",
@ -133,7 +146,7 @@ class NetgearRouter:
return False
# set already known devices to away instead of unavailable
if self.mode == MODE_ROUTER:
if self.track_devices:
device_registry = dr.async_get(self.hass)
devices = dr.async_entries_for_config_entry(device_registry, self.entry_id)
for device_entry in devices:

View File

@ -5,6 +5,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from datetime import date, datetime
from decimal import Decimal
import logging
from homeassistant.components.sensor import (
RestoreSensor,
@ -34,6 +35,8 @@ from .const import (
)
from .router import NetgearDeviceEntity, NetgearRouter, NetgearRouterEntity
_LOGGER = logging.getLogger(__name__)
SENSOR_TYPES = {
"type": SensorEntityDescription(
key="type",
@ -114,7 +117,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewWeekUpload",
@ -123,7 +126,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
NetgearSensorEntityDescription(
key="NewWeekDownload",
@ -132,7 +135,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewWeekDownload",
@ -141,7 +144,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
NetgearSensorEntityDescription(
key="NewMonthUpload",
@ -150,7 +153,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewMonthUpload",
@ -159,7 +162,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
NetgearSensorEntityDescription(
key="NewMonthDownload",
@ -168,7 +171,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewMonthDownload",
@ -177,7 +180,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
NetgearSensorEntityDescription(
key="NewLastMonthUpload",
@ -186,7 +189,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewLastMonthUpload",
@ -195,7 +198,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:upload",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
NetgearSensorEntityDescription(
key="NewLastMonthDownload",
@ -204,7 +207,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=0,
value=lambda data: data[0] if data is not None else None,
value=lambda data: data[0],
),
NetgearSensorEntityDescription(
key="NewLastMonthDownload",
@ -213,7 +216,7 @@ SENSOR_TRAFFIC_TYPES = [
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:download",
index=1,
value=lambda data: data[1] if data is not None else None,
value=lambda data: data[1],
),
]
@ -372,6 +375,17 @@ class NetgearRouterSensorEntity(NetgearRouterEntity, RestoreSensor):
@callback
def async_update_device(self) -> None:
"""Update the Netgear device."""
if self.coordinator.data is not None:
if self.coordinator.data is None:
return
data = self.coordinator.data.get(self.entity_description.key)
if data is None:
self._value = None
_LOGGER.debug(
"key '%s' not in Netgear router response '%s'",
self.entity_description.key,
data,
)
return
self._value = self.entity_description.value(data)

View File

@ -3,7 +3,7 @@
"name": "RainMachine",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/rainmachine",
"requirements": ["regenmaschine==2022.06.0"],
"requirements": ["regenmaschine==2022.06.1"],
"codeowners": ["@bachya"],
"iot_class": "local_polling",
"homekit": {

View File

@ -5,10 +5,9 @@ from sqlalchemy import text
from sqlalchemy.orm.session import Session
def db_size_bytes(session: Session, database_name: str) -> float:
def db_size_bytes(session: Session, database_name: str) -> float | None:
"""Get the mysql database size."""
return float(
session.execute(
size = session.execute(
text(
"SELECT ROUND(SUM(DATA_LENGTH + INDEX_LENGTH), 2) "
"FROM information_schema.TABLES WHERE "
@ -16,4 +15,8 @@ def db_size_bytes(session: Session, database_name: str) -> float:
),
{"database_name": database_name},
).first()[0]
)
if size is None:
return None
return float(size)

View File

@ -1,6 +1,7 @@
"""Support for balance data via the Starling Bank API."""
from __future__ import annotations
from datetime import timedelta
import logging
import requests
@ -26,6 +27,7 @@ DEFAULT_SANDBOX = False
DEFAULT_ACCOUNT_NAME = "Starling"
ICON = "mdi:currency-gbp"
SCAN_INTERVAL = timedelta(seconds=180)
ACCOUNT_SCHEMA = vol.Schema(
{

View File

@ -2,7 +2,6 @@
from __future__ import annotations
from collections.abc import Callable
from datetime import timedelta
import logging
from synology_dsm import SynologyDSM
@ -98,7 +97,7 @@ class SynoApi:
self._async_setup_api_requests()
await self._hass.async_add_executor_job(self._fetch_device_configuration)
await self.async_update()
await self.async_update(first_setup=True)
@callback
def subscribe(self, api_key: str, unique_id: str) -> Callable[[], None]:
@ -251,7 +250,7 @@ class SynoApi:
# ignore API errors during logout
pass
async def async_update(self, now: timedelta | None = None) -> None:
async def async_update(self, first_setup: bool = False) -> None:
"""Update function for updating API information."""
LOGGER.debug("Start data update for '%s'", self._entry.unique_id)
self._async_setup_api_requests()
@ -259,14 +258,22 @@ class SynoApi:
await self._hass.async_add_executor_job(
self.dsm.update, self._with_information
)
except (SynologyDSMLoginFailedException, SynologyDSMRequestException) as err:
LOGGER.warning(
"Connection error during update, fallback by reloading the entry"
)
except (
SynologyDSMLoginFailedException,
SynologyDSMRequestException,
SynologyDSMAPIErrorException,
) as err:
LOGGER.debug(
"Connection error during update of '%s' with exception: %s",
self._entry.unique_id,
err,
)
if first_setup:
raise err
LOGGER.warning(
"Connection error during update, fallback by reloading the entry"
)
await self._hass.config_entries.async_reload(self._entry.entry_id)
return

View File

@ -3,7 +3,7 @@
"name": "UniFi Protect",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/unifiprotect",
"requirements": ["pyunifiprotect==3.6.0", "unifi-discovery==1.1.3"],
"requirements": ["pyunifiprotect==3.9.2", "unifi-discovery==1.1.3"],
"dependencies": ["http"],
"codeowners": ["@briis", "@AngellusMortis", "@bdraco"],
"quality_scale": "platinum",

View File

@ -4,10 +4,6 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wallbox",
"requirements": ["wallbox==0.4.9"],
"ssdp": [],
"zeroconf": [],
"homekit": {},
"dependencies": [],
"codeowners": ["@hesselonline"],
"iot_class": "cloud_polling",
"loggers": ["wallbox"]

View File

@ -167,8 +167,12 @@ class WallboxSensor(WallboxEntity, SensorEntity):
@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
if (sensor_round := self.entity_description.precision) is not None:
"""Return the state of the sensor. Round the value when it, and the precision property are not None."""
if (
sensor_round := self.entity_description.precision
) is not None and self.coordinator.data[
self.entity_description.key
] is not None:
return cast(
StateType,
round(self.coordinator.data[self.entity_description.key], sensor_round),

View File

@ -3,7 +3,7 @@
"name": "YoLink",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/yolink",
"requirements": ["yolink-api==0.0.6"],
"requirements": ["yolink-api==0.0.8"],
"dependencies": ["auth", "application_credentials"],
"codeowners": ["@matrixd2"],
"iot_class": "cloud_push"

View File

@ -7,7 +7,7 @@ from .backports.enum import StrEnum
MAJOR_VERSION: Final = 2022
MINOR_VERSION: Final = 6
PATCH_VERSION: Final = "4"
PATCH_VERSION: Final = "5"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)

View File

@ -1538,7 +1538,7 @@ pyheos==0.7.2
pyhik==0.3.0
# homeassistant.components.hive
pyhiveapi==0.5.5
pyhiveapi==0.5.9
# homeassistant.components.homematic
pyhomematic==0.1.77
@ -1993,7 +1993,7 @@ pytrafikverket==0.2.0.1
pyudev==0.22.0
# homeassistant.components.unifiprotect
pyunifiprotect==3.6.0
pyunifiprotect==3.9.2
# homeassistant.components.uptimerobot
pyuptimerobot==22.2.0
@ -2065,7 +2065,7 @@ raincloudy==0.0.7
raspyrfm-client==1.2.8
# homeassistant.components.rainmachine
regenmaschine==2022.06.0
regenmaschine==2022.06.1
# homeassistant.components.renault
renault-api==0.1.11
@ -2486,7 +2486,7 @@ yeelight==0.7.10
yeelightsunflower==0.0.10
# homeassistant.components.yolink
yolink-api==0.0.6
yolink-api==0.0.8
# homeassistant.components.youless
youless-api==0.16

View File

@ -1029,7 +1029,7 @@ pyhaversion==22.4.1
pyheos==0.7.2
# homeassistant.components.hive
pyhiveapi==0.5.5
pyhiveapi==0.5.9
# homeassistant.components.homematic
pyhomematic==0.1.77
@ -1322,7 +1322,7 @@ pytrafikverket==0.2.0.1
pyudev==0.22.0
# homeassistant.components.unifiprotect
pyunifiprotect==3.6.0
pyunifiprotect==3.9.2
# homeassistant.components.uptimerobot
pyuptimerobot==22.2.0
@ -1364,7 +1364,7 @@ rachiopy==1.0.3
radios==0.1.1
# homeassistant.components.rainmachine
regenmaschine==2022.06.0
regenmaschine==2022.06.1
# homeassistant.components.renault
renault-api==0.1.11
@ -1638,7 +1638,7 @@ yalexs==1.1.25
yeelight==0.7.10
# homeassistant.components.yolink
yolink-api==0.0.6
yolink-api==0.0.8
# homeassistant.components.youless
youless-api==0.16

View File

@ -1,5 +1,5 @@
[metadata]
version = 2022.6.4
version = 2022.6.5
url = https://www.home-assistant.io/
[options]

View File

@ -23,6 +23,7 @@ VALID_CONFIG_1 = {feedreader.DOMAIN: {CONF_URLS: [URL]}}
VALID_CONFIG_2 = {feedreader.DOMAIN: {CONF_URLS: [URL], CONF_SCAN_INTERVAL: 60}}
VALID_CONFIG_3 = {feedreader.DOMAIN: {CONF_URLS: [URL], CONF_MAX_ENTRIES: 100}}
VALID_CONFIG_4 = {feedreader.DOMAIN: {CONF_URLS: [URL], CONF_MAX_ENTRIES: 5}}
VALID_CONFIG_5 = {feedreader.DOMAIN: {CONF_URLS: [URL], CONF_MAX_ENTRIES: 1}}
def load_fixture_bytes(src):
@ -56,6 +57,12 @@ def fixture_feed_three_events(hass):
return load_fixture_bytes("feedreader3.xml")
@pytest.fixture(name="feed_atom_event")
def fixture_feed_atom_event(hass):
"""Load test feed data for atom event."""
return load_fixture_bytes("feedreader5.xml")
@pytest.fixture(name="events")
async def fixture_events(hass):
"""Fixture that catches alexa events."""
@ -98,7 +105,7 @@ async def test_setup_max_entries(hass):
async def test_feed(hass, events, feed_one_event):
"""Test simple feed with valid data."""
"""Test simple rss feed with valid data."""
with patch(
"feedparser.http.get",
return_value=feed_one_event,
@ -120,6 +127,29 @@ async def test_feed(hass, events, feed_one_event):
assert events[0].data.published_parsed.tm_min == 10
async def test_atom_feed(hass, events, feed_atom_event):
"""Test simple atom feed with valid data."""
with patch(
"feedparser.http.get",
return_value=feed_atom_event,
):
assert await async_setup_component(hass, feedreader.DOMAIN, VALID_CONFIG_5)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].data.title == "Atom-Powered Robots Run Amok"
assert events[0].data.description == "Some text."
assert events[0].data.link == "http://example.org/2003/12/13/atom03"
assert events[0].data.id == "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"
assert events[0].data.updated_parsed.tm_year == 2003
assert events[0].data.updated_parsed.tm_mon == 12
assert events[0].data.updated_parsed.tm_mday == 13
assert events[0].data.updated_parsed.tm_hour == 18
assert events[0].data.updated_parsed.tm_min == 30
async def test_feed_updates(hass, events, feed_one_event, feed_two_event):
"""Test feed updates."""
side_effect = [

View File

@ -33,16 +33,6 @@ async def test_import_flow(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[
"mock-device-group-key",
"mock-device-key",
"mock-device-password",
],
), patch(
"homeassistant.components.hive.async_setup", return_value=True
) as mock_setup, patch(
@ -67,11 +57,6 @@ async def test_import_flow(hass):
},
"ChallengeName": "SUCCESS",
},
"device_data": [
"mock-device-group-key",
"mock-device-key",
"mock-device-password",
],
}
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert len(mock_setup.mock_calls) == 1
@ -96,16 +81,6 @@ async def test_user_flow(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[
"mock-device-group-key",
"mock-device-key",
"mock-device-password",
],
), patch(
"homeassistant.components.hive.async_setup", return_value=True
) as mock_setup, patch(
@ -130,11 +105,6 @@ async def test_user_flow(hass):
},
"ChallengeName": "SUCCESS",
},
"device_data": [
"mock-device-group-key",
"mock-device-key",
"mock-device-password",
],
}
assert len(mock_setup.mock_calls) == 1

View File

@ -1256,12 +1256,8 @@ async def test_tilt_defaults(hass, mqtt_mock_entry_with_yaml_config):
await mqtt_mock_entry_with_yaml_config()
state_attributes_dict = hass.states.get("cover.test").attributes
assert ATTR_CURRENT_TILT_POSITION in state_attributes_dict
current_cover_position = hass.states.get("cover.test").attributes[
ATTR_CURRENT_TILT_POSITION
]
assert current_cover_position == STATE_UNKNOWN
# Tilt position is not yet known
assert ATTR_CURRENT_TILT_POSITION not in state_attributes_dict
async def test_tilt_via_invocation_defaults(hass, mqtt_mock_entry_with_yaml_config):

View File

@ -168,7 +168,7 @@ async def sensor_fixture(
sensor_obj.motion_detected_at = now - timedelta(hours=1)
sensor_obj.open_status_changed_at = now - timedelta(hours=1)
sensor_obj.alarm_triggered_at = now - timedelta(hours=1)
sensor_obj.tampering_detected_at = now - timedelta(hours=1)
sensor_obj.tampering_detected_at = None
mock_entry.api.bootstrap.reset_objects()
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
@ -204,7 +204,7 @@ async def sensor_none_fixture(
sensor_obj.mount_type = MountType.LEAK
sensor_obj.battery_status.is_low = False
sensor_obj.alarm_settings.is_enabled = False
sensor_obj.tampering_detected_at = now - timedelta(hours=1)
sensor_obj.tampering_detected_at = None
mock_entry.api.bootstrap.reset_objects()
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []

18
tests/fixtures/feedreader5.xml vendored Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<feed
xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<link href="http://example.org/"/>
<updated>2003-12-13T18:30:02Z</updated>
<author>
<name>John Doe</name>
</author>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<entry>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
</entry>
</feed>