1
mirror of https://github.com/home-assistant/core synced 2024-09-06 10:29:55 +02:00

Use entity_registry_enabled_default for Nut sensors (#56854)

This commit is contained in:
ollo69 2021-10-13 23:33:03 +02:00 committed by GitHub
parent b220ab6e91
commit b54fc0229d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 95 deletions

View File

@ -39,6 +39,11 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Network UPS Tools (NUT) from a config entry."""
# strip out the stale options CONF_RESOURCES
if CONF_RESOURCES in entry.options:
new_options = {k: v for k, v in entry.options.items() if k != CONF_RESOURCES}
hass.config_entries.async_update_entry(entry, options=new_options)
config = entry.data
host = config[CONF_HOST]
port = config[CONF_PORT]
@ -156,13 +161,6 @@ def _unique_id_from_status(status):
return "_".join(unique_id_group)
def find_resources_in_config_entry(config_entry):
"""Find the configured resources in the config entry."""
if CONF_RESOURCES in config_entry.options:
return config_entry.options[CONF_RESOURCES]
return config_entry.data[CONF_RESOURCES]
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@ -17,7 +17,7 @@ from homeassistant.const import (
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from . import PyNUTData, find_resources_in_config_entry
from . import PyNUTData
from .const import (
DEFAULT_HOST,
DEFAULT_PORT,
@ -229,35 +229,17 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
resources = find_resources_in_config_entry(self.config_entry)
scan_interval = self.config_entry.options.get(
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
)
errors = {}
try:
info = await validate_input(self.hass, self.config_entry.data)
except CannotConnect:
errors[CONF_BASE] = "cannot_connect"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors[CONF_BASE] = "unknown"
base_schema = {
vol.Optional(CONF_SCAN_INTERVAL, default=scan_interval): vol.All(
vol.Coerce(int), vol.Clamp(min=10, max=300)
)
}
if errors:
return self.async_show_form(step_id="abort", errors=errors)
base_schema = _resource_schema_base(info["available_resources"], resources)
base_schema[
vol.Optional(CONF_SCAN_INTERVAL, default=scan_interval)
] = cv.positive_int
return self.async_show_form(
step_id="init", data_schema=vol.Schema(base_schema), errors=errors
)
async def async_step_abort(self, user_input=None):
"""Abort options flow."""
return self.async_create_entry(title="", data=self.config_entry.options)
return self.async_show_form(step_id="init", data_schema=vol.Schema(base_schema))
class CannotConnect(exceptions.HomeAssistantError):

View File

@ -42,39 +42,29 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
data = pynut_data[PYNUT_DATA]
status = data.status
entities = []
enabled_resources = [
resource.lower() for resource in config_entry.data[CONF_RESOURCES]
]
resources = [sensor_id for sensor_id in SENSOR_TYPES if sensor_id in status]
# Display status is a special case that falls back to the status value
# of the UPS instead.
if KEY_STATUS in resources:
resources.append(KEY_STATUS_DISPLAY)
if CONF_RESOURCES in config_entry.options:
resources = config_entry.options[CONF_RESOURCES]
else:
resources = config_entry.data[CONF_RESOURCES]
for resource in resources:
sensor_type = resource.lower()
# Display status is a special case that falls back to the status value
# of the UPS instead.
if sensor_type in status or (
sensor_type == KEY_STATUS_DISPLAY and KEY_STATUS in status
):
entities.append(
NUTSensor(
coordinator,
data,
name.title(),
SENSOR_TYPES[sensor_type],
unique_id,
manufacturer,
model,
firmware,
)
)
else:
_LOGGER.info(
"Sensor type: %s does not appear in the NUT status "
"output, cannot add",
sensor_type,
)
entities = [
NUTSensor(
coordinator,
data,
name.title(),
SENSOR_TYPES[sensor_type],
unique_id,
manufacturer,
model,
firmware,
sensor_type in enabled_resources,
)
for sensor_type in resources
]
async_add_entities(entities, True)
@ -92,6 +82,7 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
manufacturer: str | None,
model: str | None,
firmware: str | None,
enabled_default: bool,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
@ -102,6 +93,7 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
self._device_name = name
self._data = data
self._unique_id = unique_id
self._attr_entity_registry_enabled_default = enabled_default
self._attr_name = f"{name} {sensor_description.name}"
if unique_id is not None:

View File

@ -35,16 +35,10 @@
"options": {
"step": {
"init": {
"description": "Choose Sensor Resources.",
"data": {
"resources": "Resources",
"scan_interval": "Scan Interval (seconds)"
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}
}
}

View File

@ -33,17 +33,11 @@
}
},
"options": {
"error": {
"cannot_connect": "Failed to connect",
"unknown": "Unexpected error"
},
"step": {
"init": {
"data": {
"resources": "Resources",
"scan_interval": "Scan Interval (seconds)"
},
"description": "Choose Sensor Resources."
}
}
}
}

View File

@ -294,37 +294,25 @@ async def test_options_flow(hass):
domain=DOMAIN,
unique_id="abcde12345",
data=VALID_CONFIG,
options={CONF_RESOURCES: ["battery.charge"]},
)
config_entry.add_to_hass(hass)
mock_pynut = _get_mock_pynutclient(
list_vars={"battery.voltage": "voltage"}, list_ups=["ups1"]
)
with patch(
"homeassistant.components.nut.PyNUTClient",
return_value=mock_pynut,
), patch("homeassistant.components.nut.async_setup_entry", return_value=True):
with patch("homeassistant.components.nut.async_setup_entry", return_value=True):
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input={CONF_RESOURCES: ["battery.voltage"]}
result["flow_id"], user_input={}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert config_entry.options == {
CONF_RESOURCES: ["battery.voltage"],
CONF_SCAN_INTERVAL: 60,
}
with patch(
"homeassistant.components.nut.PyNUTClient",
return_value=mock_pynut,
), patch("homeassistant.components.nut.async_setup_entry", return_value=True):
with patch("homeassistant.components.nut.async_setup_entry", return_value=True):
result2 = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
@ -332,11 +320,10 @@ async def test_options_flow(hass):
result2 = await hass.config_entries.options.async_configure(
result2["flow_id"],
user_input={CONF_RESOURCES: ["battery.voltage"], CONF_SCAN_INTERVAL: 12},
user_input={CONF_SCAN_INTERVAL: 12},
)
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert config_entry.options == {
CONF_RESOURCES: ["battery.voltage"],
CONF_SCAN_INTERVAL: 12,
}

View File

@ -202,3 +202,16 @@ async def test_blazer_usb(hass):
assert all(
state.attributes[key] == expected_attributes[key] for key in expected_attributes
)
async def test_stale_options(hass):
"""Test creation of sensors with stale options to remove."""
config_entry = await async_init_integration(
hass, "blazer_usb", ["battery.charge"], True
)
registry = er.async_get(hass)
entry = registry.async_get("sensor.ups1_battery_charge")
assert entry
assert entry.unique_id == f"{config_entry.entry_id}_battery.charge"
assert config_entry.options == {}

View File

@ -18,7 +18,7 @@ def _get_mock_pynutclient(list_vars=None, list_ups=None):
async def async_init_integration(
hass: HomeAssistant, ups_fixture: str, resources: list
hass: HomeAssistant, ups_fixture: str, resources: list, add_options: bool = False
) -> MockConfigEntry:
"""Set up the nexia integration in Home Assistant."""
@ -34,6 +34,7 @@ async def async_init_integration(
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: "mock", CONF_PORT: "mock", CONF_RESOURCES: resources},
options={CONF_RESOURCES: resources} if add_options else {},
)
entry.add_to_hass(hass)