Fallback to None for literal "Blank" serial number for APCUPSD integration (#136297)

* Fallback to None for Blank serial number

* Fix comments
This commit is contained in:
Yuxin Wang 2025-01-22 23:10:52 -05:00 committed by Franck Nijhof
parent 0caa1ed825
commit 2e4a19b058
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
3 changed files with 12 additions and 3 deletions

View File

@ -44,7 +44,10 @@ class APCUPSdData(dict[str, str]):
@property @property
def serial_no(self) -> str | None: def serial_no(self) -> str | None:
"""Return the unique serial number of the UPS, if available.""" """Return the unique serial number of the UPS, if available."""
return self.get("SERIALNO") sn = self.get("SERIALNO")
# We had user reports that some UPS models simply return "Blank" as serial number, in
# which case we fall back to `None` to indicate that it is actually not available.
return None if sn == "Blank" else sn
class APCUPSdCoordinator(DataUpdateCoordinator[APCUPSdData]): class APCUPSdCoordinator(DataUpdateCoordinator[APCUPSdData]):

View File

@ -125,6 +125,8 @@ async def test_flow_works(hass: HomeAssistant) -> None:
({"UPSNAME": "Friendly Name"}, "Friendly Name"), ({"UPSNAME": "Friendly Name"}, "Friendly Name"),
({"MODEL": "MODEL X"}, "MODEL X"), ({"MODEL": "MODEL X"}, "MODEL X"),
({"SERIALNO": "ZZZZ"}, "ZZZZ"), ({"SERIALNO": "ZZZZ"}, "ZZZZ"),
# Some models report "Blank" as serial number, which we should treat it as not reported.
({"SERIALNO": "Blank"}, "APC UPS"),
({}, "APC UPS"), ({}, "APC UPS"),
], ],
) )

View File

@ -31,6 +31,8 @@ from tests.common import MockConfigEntry, async_fire_time_changed
# Does not contain either "SERIALNO" field. # Does not contain either "SERIALNO" field.
# We should _not_ create devices for the entities and their IDs will not have prefixes. # We should _not_ create devices for the entities and their IDs will not have prefixes.
MOCK_MINIMAL_STATUS, MOCK_MINIMAL_STATUS,
# Some models report "Blank" as SERIALNO, but we should treat it as not reported.
MOCK_MINIMAL_STATUS | {"SERIALNO": "Blank"},
], ],
) )
async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> None: async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> None:
@ -41,7 +43,7 @@ async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> No
await async_init_integration(hass, status=status) await async_init_integration(hass, status=status)
prefix = "" prefix = ""
if "SERIALNO" in status: if "SERIALNO" in status and status["SERIALNO"] != "Blank":
prefix = slugify(status.get("UPSNAME", "APC UPS")) + "_" prefix = slugify(status.get("UPSNAME", "APC UPS")) + "_"
# Verify successful setup by querying the status sensor. # Verify successful setup by querying the status sensor.
@ -56,6 +58,8 @@ async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> No
[ [
# We should not create device entries if SERIALNO is not reported. # We should not create device entries if SERIALNO is not reported.
MOCK_MINIMAL_STATUS, MOCK_MINIMAL_STATUS,
# Some models report "Blank" as SERIALNO, but we should treat it as not reported.
MOCK_MINIMAL_STATUS | {"SERIALNO": "Blank"},
# We should set the device name to be the friendly UPSNAME field if available. # We should set the device name to be the friendly UPSNAME field if available.
MOCK_MINIMAL_STATUS | {"SERIALNO": "XXXX", "UPSNAME": "MyUPS"}, MOCK_MINIMAL_STATUS | {"SERIALNO": "XXXX", "UPSNAME": "MyUPS"},
# Otherwise, we should fall back to default device name --- "APC UPS". # Otherwise, we should fall back to default device name --- "APC UPS".
@ -71,7 +75,7 @@ async def test_device_entry(
await async_init_integration(hass, status=status) await async_init_integration(hass, status=status)
# Verify device info is properly set up. # Verify device info is properly set up.
if "SERIALNO" not in status: if "SERIALNO" not in status or status["SERIALNO"] == "Blank":
assert len(device_registry.devices) == 0 assert len(device_registry.devices) == 0
return return