mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Remove deprecated platform yaml in Scrape (#90272)
* Deprecate platform yaml * typing * DiscoveryInfoType
This commit is contained in:
parent
c3717f8182
commit
624860da0e
@ -1,44 +1,23 @@
|
|||||||
"""Support for getting data from websites with scraping."""
|
"""Support for getting data from websites with scraping."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any, cast
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.rest import RESOURCE_SCHEMA, create_rest_data_from_config
|
from homeassistant.components.sensor import SensorDeviceClass
|
||||||
from homeassistant.components.sensor import (
|
|
||||||
CONF_STATE_CLASS,
|
|
||||||
DEVICE_CLASSES_SCHEMA,
|
|
||||||
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
|
|
||||||
STATE_CLASSES_SCHEMA,
|
|
||||||
SensorDeviceClass,
|
|
||||||
)
|
|
||||||
from homeassistant.components.sensor.helpers import async_parse_date_datetime
|
from homeassistant.components.sensor.helpers import async_parse_date_datetime
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_ATTRIBUTE,
|
CONF_ATTRIBUTE,
|
||||||
CONF_AUTHENTICATION,
|
|
||||||
CONF_DEVICE_CLASS,
|
|
||||||
CONF_HEADERS,
|
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_RESOURCE,
|
|
||||||
CONF_SCAN_INTERVAL,
|
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
|
||||||
CONF_USERNAME,
|
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
CONF_VERIFY_SSL,
|
|
||||||
HTTP_BASIC_AUTHENTICATION,
|
|
||||||
HTTP_DIGEST_AUTHENTICATION,
|
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import PlatformNotReady
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.template_entity import (
|
from homeassistant.helpers.template_entity import (
|
||||||
TEMPLATE_SENSOR_BASE_SCHEMA,
|
TEMPLATE_SENSOR_BASE_SCHEMA,
|
||||||
@ -47,43 +26,11 @@ from homeassistant.helpers.template_entity import (
|
|||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from .const import (
|
from .const import CONF_INDEX, CONF_SELECT, DOMAIN
|
||||||
CONF_INDEX,
|
|
||||||
CONF_SELECT,
|
|
||||||
DEFAULT_NAME,
|
|
||||||
DEFAULT_SCAN_INTERVAL,
|
|
||||||
DEFAULT_VERIFY_SSL,
|
|
||||||
DOMAIN,
|
|
||||||
)
|
|
||||||
from .coordinator import ScrapeCoordinator
|
from .coordinator import ScrapeCoordinator
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
# Linked to the loading of the page (can be linked to RestData)
|
|
||||||
vol.Optional(CONF_AUTHENTICATION): vol.In(
|
|
||||||
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
|
|
||||||
vol.Optional(CONF_PASSWORD): cv.string,
|
|
||||||
vol.Required(CONF_RESOURCE): cv.string,
|
|
||||||
vol.Optional(CONF_USERNAME): cv.string,
|
|
||||||
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
|
|
||||||
# Linked to the parsing of the page (specific to scrape)
|
|
||||||
vol.Optional(CONF_ATTRIBUTE): cv.string,
|
|
||||||
vol.Optional(CONF_INDEX, default=0): cv.positive_int,
|
|
||||||
vol.Required(CONF_SELECT): cv.string,
|
|
||||||
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
|
||||||
# Linked to the sensor definition (can be linked to TemplateSensor)
|
|
||||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA,
|
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
|
||||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -92,33 +39,9 @@ async def async_setup_platform(
|
|||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Web scrape sensor."""
|
"""Set up the Web scrape sensor."""
|
||||||
coordinator: ScrapeCoordinator
|
discovery_info = cast(DiscoveryInfoType, discovery_info)
|
||||||
sensors_config: list[ConfigType]
|
coordinator: ScrapeCoordinator = discovery_info["coordinator"]
|
||||||
if discovery_info is None:
|
sensors_config: list[ConfigType] = discovery_info["configs"]
|
||||||
async_create_issue(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
"moved_yaml",
|
|
||||||
breaks_in_ha_version="2022.12.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="moved_yaml",
|
|
||||||
)
|
|
||||||
resource_config = vol.Schema(RESOURCE_SCHEMA, extra=vol.REMOVE_EXTRA)(config)
|
|
||||||
rest = create_rest_data_from_config(hass, resource_config)
|
|
||||||
|
|
||||||
scan_interval: timedelta = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
|
||||||
coordinator = ScrapeCoordinator(hass, rest, scan_interval)
|
|
||||||
|
|
||||||
sensors_config = [
|
|
||||||
vol.Schema(TEMPLATE_SENSOR_BASE_SCHEMA.schema, extra=vol.ALLOW_EXTRA)(
|
|
||||||
config
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
else:
|
|
||||||
coordinator = discovery_info["coordinator"]
|
|
||||||
sensors_config = discovery_info["configs"]
|
|
||||||
|
|
||||||
await coordinator.async_refresh()
|
await coordinator.async_refresh()
|
||||||
if coordinator.data is None:
|
if coordinator.data is None:
|
||||||
|
@ -121,11 +121,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"issues": {
|
|
||||||
"moved_yaml": {
|
|
||||||
"title": "The Scrape YAML configuration has been moved",
|
|
||||||
"description": "Configuring Scrape using YAML has been moved to integration key.\n\nYour existing YAML configuration will be working for 2 more versions.\n\nMigrate your YAML configuration to the integration key according to the documentation."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,65 +29,13 @@ def return_integration_config(
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def return_config(
|
|
||||||
select,
|
|
||||||
name,
|
|
||||||
*,
|
|
||||||
attribute=None,
|
|
||||||
index=None,
|
|
||||||
template=None,
|
|
||||||
uom=None,
|
|
||||||
device_class=None,
|
|
||||||
state_class=None,
|
|
||||||
authentication=None,
|
|
||||||
username=None,
|
|
||||||
password=None,
|
|
||||||
headers=None,
|
|
||||||
unique_id=None,
|
|
||||||
remove_platform=False,
|
|
||||||
) -> dict[str, dict[str, Any]]:
|
|
||||||
"""Return config."""
|
|
||||||
config = {
|
|
||||||
"platform": "scrape",
|
|
||||||
"resource": "https://www.home-assistant.io",
|
|
||||||
"select": select,
|
|
||||||
"name": name,
|
|
||||||
"index": 0,
|
|
||||||
"verify_ssl": True,
|
|
||||||
}
|
|
||||||
if remove_platform:
|
|
||||||
config.pop("platform")
|
|
||||||
if attribute:
|
|
||||||
config["attribute"] = attribute
|
|
||||||
if index:
|
|
||||||
config["index"] = index
|
|
||||||
if template:
|
|
||||||
config["value_template"] = template
|
|
||||||
if uom:
|
|
||||||
config["unit_of_measurement"] = uom
|
|
||||||
if device_class:
|
|
||||||
config["device_class"] = device_class
|
|
||||||
if state_class:
|
|
||||||
config["state_class"] = state_class
|
|
||||||
if authentication:
|
|
||||||
config["authentication"] = authentication
|
|
||||||
if username:
|
|
||||||
config["username"] = username
|
|
||||||
config["password"] = password
|
|
||||||
if headers:
|
|
||||||
config["headers"] = headers
|
|
||||||
if unique_id:
|
|
||||||
config["unique_id"] = unique_id
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
class MockRestData:
|
class MockRestData:
|
||||||
"""Mock RestData."""
|
"""Mock RestData."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
payload,
|
payload,
|
||||||
):
|
) -> None:
|
||||||
"""Init RestDataMock."""
|
"""Init RestDataMock."""
|
||||||
self.data: str | None = None
|
self.data: str | None = None
|
||||||
self.payload = payload
|
self.payload = payload
|
||||||
|
@ -9,7 +9,6 @@ import pytest
|
|||||||
from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL
|
from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
CONF_STATE_CLASS,
|
CONF_STATE_CLASS,
|
||||||
DOMAIN as SENSOR_DOMAIN,
|
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
@ -24,7 +23,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from . import MockRestData, return_config, return_integration_config
|
from . import MockRestData, return_integration_config
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||||
|
|
||||||
@ -53,70 +52,6 @@ async def test_scrape_sensor(hass: HomeAssistant) -> None:
|
|||||||
assert state.state == "Current Version: 2021.12.10"
|
assert state.state == "Current Version: 2021.12.10"
|
||||||
|
|
||||||
|
|
||||||
async def test_scrape_sensor_platform_yaml(hass: HomeAssistant) -> None:
|
|
||||||
"""Test Scrape sensor load from sensor platform."""
|
|
||||||
config = {
|
|
||||||
SENSOR_DOMAIN: [
|
|
||||||
return_config(
|
|
||||||
select=".return",
|
|
||||||
name="Auth page",
|
|
||||||
username="user@secret.com",
|
|
||||||
password="12345678",
|
|
||||||
authentication="digest",
|
|
||||||
),
|
|
||||||
return_config(
|
|
||||||
select=".return",
|
|
||||||
name="Auth page2",
|
|
||||||
username="user@secret.com",
|
|
||||||
password="12345678",
|
|
||||||
template="{{value}}",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
mocker = MockRestData("test_scrape_sensor_authentication")
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.rest.RestData",
|
|
||||||
return_value=mocker,
|
|
||||||
):
|
|
||||||
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get("sensor.auth_page")
|
|
||||||
assert state.state == "secret text"
|
|
||||||
state2 = hass.states.get("sensor.auth_page2")
|
|
||||||
assert state2.state == "secret text"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_scrape_sensor_platform_yaml_no_data(
|
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
|
||||||
) -> None:
|
|
||||||
"""Test Scrape sensor load from sensor platform fetching no data."""
|
|
||||||
config = {
|
|
||||||
SENSOR_DOMAIN: [
|
|
||||||
return_config(
|
|
||||||
select=".return",
|
|
||||||
name="Auth page",
|
|
||||||
username="user@secret.com",
|
|
||||||
password="12345678",
|
|
||||||
authentication="digest",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
mocker = MockRestData("test_scrape_sensor_no_data")
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.rest.RestData",
|
|
||||||
return_value=mocker,
|
|
||||||
):
|
|
||||||
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get("sensor.auth_page")
|
|
||||||
assert not state
|
|
||||||
assert "Platform scrape not ready yet: None; Retrying in background" in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
async def test_scrape_sensor_value_template(hass: HomeAssistant) -> None:
|
async def test_scrape_sensor_value_template(hass: HomeAssistant) -> None:
|
||||||
"""Test Scrape sensor with value template."""
|
"""Test Scrape sensor with value template."""
|
||||||
config = {
|
config = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user