mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 14:47:38 +00:00
Use entity_registry_enabled_default for Nut sensors (#56854)
This commit is contained in:
parent
b220ab6e91
commit
b54fc0229d
@ -39,6 +39,11 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Network UPS Tools (NUT) from a config entry."""
|
"""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
|
config = entry.data
|
||||||
host = config[CONF_HOST]
|
host = config[CONF_HOST]
|
||||||
port = config[CONF_PORT]
|
port = config[CONF_PORT]
|
||||||
@ -156,13 +161,6 @@ def _unique_id_from_status(status):
|
|||||||
return "_".join(unique_id_group)
|
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:
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
@ -17,7 +17,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
from . import PyNUTData, find_resources_in_config_entry
|
from . import PyNUTData
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_HOST,
|
DEFAULT_HOST,
|
||||||
DEFAULT_PORT,
|
DEFAULT_PORT,
|
||||||
@ -229,35 +229,17 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
return self.async_create_entry(title="", data=user_input)
|
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(
|
scan_interval = self.config_entry.options.get(
|
||||||
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
|
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
|
||||||
)
|
)
|
||||||
|
|
||||||
errors = {}
|
base_schema = {
|
||||||
try:
|
vol.Optional(CONF_SCAN_INTERVAL, default=scan_interval): vol.All(
|
||||||
info = await validate_input(self.hass, self.config_entry.data)
|
vol.Coerce(int), vol.Clamp(min=10, max=300)
|
||||||
except CannotConnect:
|
|
||||||
errors[CONF_BASE] = "cannot_connect"
|
|
||||||
except Exception: # pylint: disable=broad-except
|
|
||||||
_LOGGER.exception("Unexpected exception")
|
|
||||||
errors[CONF_BASE] = "unknown"
|
|
||||||
|
|
||||||
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):
|
return self.async_show_form(step_id="init", data_schema=vol.Schema(base_schema))
|
||||||
"""Abort options flow."""
|
|
||||||
return self.async_create_entry(title="", data=self.config_entry.options)
|
|
||||||
|
|
||||||
|
|
||||||
class CannotConnect(exceptions.HomeAssistantError):
|
class CannotConnect(exceptions.HomeAssistantError):
|
||||||
|
@ -42,22 +42,16 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
data = pynut_data[PYNUT_DATA]
|
data = pynut_data[PYNUT_DATA]
|
||||||
status = data.status
|
status = data.status
|
||||||
|
|
||||||
entities = []
|
enabled_resources = [
|
||||||
|
resource.lower() for resource in config_entry.data[CONF_RESOURCES]
|
||||||
if CONF_RESOURCES in config_entry.options:
|
]
|
||||||
resources = config_entry.options[CONF_RESOURCES]
|
resources = [sensor_id for sensor_id in SENSOR_TYPES if sensor_id in status]
|
||||||
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
|
# Display status is a special case that falls back to the status value
|
||||||
# of the UPS instead.
|
# of the UPS instead.
|
||||||
if sensor_type in status or (
|
if KEY_STATUS in resources:
|
||||||
sensor_type == KEY_STATUS_DISPLAY and KEY_STATUS in status
|
resources.append(KEY_STATUS_DISPLAY)
|
||||||
):
|
|
||||||
entities.append(
|
entities = [
|
||||||
NUTSensor(
|
NUTSensor(
|
||||||
coordinator,
|
coordinator,
|
||||||
data,
|
data,
|
||||||
@ -67,14 +61,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
manufacturer,
|
manufacturer,
|
||||||
model,
|
model,
|
||||||
firmware,
|
firmware,
|
||||||
|
sensor_type in enabled_resources,
|
||||||
)
|
)
|
||||||
)
|
for sensor_type in resources
|
||||||
else:
|
]
|
||||||
_LOGGER.info(
|
|
||||||
"Sensor type: %s does not appear in the NUT status "
|
|
||||||
"output, cannot add",
|
|
||||||
sensor_type,
|
|
||||||
)
|
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
@ -92,6 +82,7 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
|
|||||||
manufacturer: str | None,
|
manufacturer: str | None,
|
||||||
model: str | None,
|
model: str | None,
|
||||||
firmware: str | None,
|
firmware: str | None,
|
||||||
|
enabled_default: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
@ -102,6 +93,7 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
|
|||||||
self._device_name = name
|
self._device_name = name
|
||||||
self._data = data
|
self._data = data
|
||||||
self._unique_id = unique_id
|
self._unique_id = unique_id
|
||||||
|
self._attr_entity_registry_enabled_default = enabled_default
|
||||||
|
|
||||||
self._attr_name = f"{name} {sensor_description.name}"
|
self._attr_name = f"{name} {sensor_description.name}"
|
||||||
if unique_id is not None:
|
if unique_id is not None:
|
||||||
|
@ -35,16 +35,10 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"description": "Choose Sensor Resources.",
|
|
||||||
"data": {
|
"data": {
|
||||||
"resources": "Resources",
|
|
||||||
"scan_interval": "Scan Interval (seconds)"
|
"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": {
|
"options": {
|
||||||
"error": {
|
|
||||||
"cannot_connect": "Failed to connect",
|
|
||||||
"unknown": "Unexpected error"
|
|
||||||
},
|
|
||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"resources": "Resources",
|
|
||||||
"scan_interval": "Scan Interval (seconds)"
|
"scan_interval": "Scan Interval (seconds)"
|
||||||
},
|
}
|
||||||
"description": "Choose Sensor Resources."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,37 +294,25 @@ async def test_options_flow(hass):
|
|||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
unique_id="abcde12345",
|
unique_id="abcde12345",
|
||||||
data=VALID_CONFIG,
|
data=VALID_CONFIG,
|
||||||
options={CONF_RESOURCES: ["battery.charge"]},
|
|
||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
mock_pynut = _get_mock_pynutclient(
|
with patch("homeassistant.components.nut.async_setup_entry", return_value=True):
|
||||||
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):
|
|
||||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
result = await hass.config_entries.options.async_configure(
|
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 result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert config_entry.options == {
|
assert config_entry.options == {
|
||||||
CONF_RESOURCES: ["battery.voltage"],
|
|
||||||
CONF_SCAN_INTERVAL: 60,
|
CONF_SCAN_INTERVAL: 60,
|
||||||
}
|
}
|
||||||
|
|
||||||
with patch(
|
with patch("homeassistant.components.nut.async_setup_entry", return_value=True):
|
||||||
"homeassistant.components.nut.PyNUTClient",
|
|
||||||
return_value=mock_pynut,
|
|
||||||
), patch("homeassistant.components.nut.async_setup_entry", return_value=True):
|
|
||||||
result2 = await hass.config_entries.options.async_init(config_entry.entry_id)
|
result2 = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
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 = await hass.config_entries.options.async_configure(
|
||||||
result2["flow_id"],
|
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 result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert config_entry.options == {
|
assert config_entry.options == {
|
||||||
CONF_RESOURCES: ["battery.voltage"],
|
|
||||||
CONF_SCAN_INTERVAL: 12,
|
CONF_SCAN_INTERVAL: 12,
|
||||||
}
|
}
|
||||||
|
@ -202,3 +202,16 @@ async def test_blazer_usb(hass):
|
|||||||
assert all(
|
assert all(
|
||||||
state.attributes[key] == expected_attributes[key] for key in expected_attributes
|
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(
|
async def async_init_integration(
|
||||||
hass: HomeAssistant, ups_fixture: str, resources: list
|
hass: HomeAssistant, ups_fixture: str, resources: list, add_options: bool = False
|
||||||
) -> MockConfigEntry:
|
) -> MockConfigEntry:
|
||||||
"""Set up the nexia integration in Home Assistant."""
|
"""Set up the nexia integration in Home Assistant."""
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ async def async_init_integration(
|
|||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
data={CONF_HOST: "mock", CONF_PORT: "mock", CONF_RESOURCES: resources},
|
data={CONF_HOST: "mock", CONF_PORT: "mock", CONF_RESOURCES: resources},
|
||||||
|
options={CONF_RESOURCES: resources} if add_options else {},
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user