Use entity_registry_enabled_default for Nut sensors (#56854)
parent
b220ab6e91
commit
b54fc0229d
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 == {}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue