Skip to content

Commit b8e3d57

Browse files
authored
Deprecate useless sensors in APCUPSD integration (home-assistant#151525)
1 parent 0de2a16 commit b8e3d57

File tree

5 files changed

+421
-3
lines changed

5 files changed

+421
-3
lines changed

homeassistant/components/apcupsd/const.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,26 @@
77

88
# Field name of last self test retrieved from apcupsd.
99
LAST_S_TEST: Final = "laststest"
10+
11+
# Mapping of deprecated sensor keys (as reported by apcupsd, lower-cased) to their deprecation
12+
# repair issue translation keys.
13+
DEPRECATED_SENSORS: Final = {
14+
"apc": "apc_deprecated",
15+
"end apc": "date_deprecated",
16+
"date": "date_deprecated",
17+
"apcmodel": "available_via_device_info",
18+
"model": "available_via_device_info",
19+
"firmware": "available_via_device_info",
20+
"version": "available_via_device_info",
21+
"upsname": "available_via_device_info",
22+
"serialno": "available_via_device_info",
23+
}
24+
25+
AVAILABLE_VIA_DEVICE_ATTR: Final = {
26+
"apcmodel": "model",
27+
"model": "model",
28+
"firmware": "hw_version",
29+
"version": "sw_version",
30+
"upsname": "name",
31+
"serialno": "serial_number",
32+
}

homeassistant/components/apcupsd/sensor.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import logging
66

7+
from homeassistant.components.automation import automations_with_entity
8+
from homeassistant.components.script import scripts_with_entity
79
from homeassistant.components.sensor import (
810
SensorDeviceClass,
911
SensorEntity,
@@ -22,9 +24,11 @@
2224
UnitOfTime,
2325
)
2426
from homeassistant.core import HomeAssistant, callback
27+
from homeassistant.helpers import entity_registry as er
2528
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
29+
import homeassistant.helpers.issue_registry as ir
2630

27-
from .const import LAST_S_TEST
31+
from .const import AVAILABLE_VIA_DEVICE_ATTR, DEPRECATED_SENSORS, DOMAIN, LAST_S_TEST
2832
from .coordinator import APCUPSdConfigEntry, APCUPSdCoordinator
2933
from .entity import APCUPSdEntity
3034

@@ -528,3 +532,62 @@ def _update_attrs(self) -> None:
528532
self._attr_native_value, inferred_unit = infer_unit(self.coordinator.data[key])
529533
if not self.native_unit_of_measurement:
530534
self._attr_native_unit_of_measurement = inferred_unit
535+
536+
async def async_added_to_hass(self) -> None:
537+
"""Handle when entity is added to Home Assistant.
538+
539+
If this is a deprecated sensor entity, create a repair issue to guide
540+
the user to disable it.
541+
"""
542+
await super().async_added_to_hass()
543+
544+
if not self.enabled:
545+
return
546+
547+
reason = DEPRECATED_SENSORS.get(self.entity_description.key)
548+
if not reason:
549+
return
550+
551+
automations = automations_with_entity(self.hass, self.entity_id)
552+
scripts = scripts_with_entity(self.hass, self.entity_id)
553+
if not automations and not scripts:
554+
return
555+
556+
entity_registry = er.async_get(self.hass)
557+
items = [
558+
f"- [{entry.name or entry.original_name or entity_id}]"
559+
f"(/config/{integration}/edit/{entry.unique_id or entity_id.split('.', 1)[-1]})"
560+
for integration, entities in (
561+
("automation", automations),
562+
("script", scripts),
563+
)
564+
for entity_id in entities
565+
if (entry := entity_registry.async_get(entity_id))
566+
]
567+
placeholders = {
568+
"entity_name": str(self.name or self.entity_id),
569+
"entity_id": self.entity_id,
570+
"items": "\n".join(items),
571+
}
572+
if via_attr := AVAILABLE_VIA_DEVICE_ATTR.get(self.entity_description.key):
573+
placeholders["available_via_device_attr"] = via_attr
574+
if device_entry := self.device_entry:
575+
placeholders["device_id"] = device_entry.id
576+
577+
ir.async_create_issue(
578+
self.hass,
579+
DOMAIN,
580+
f"{reason}_{self.entity_id}",
581+
breaks_in_ha_version="2026.6.0",
582+
is_fixable=False,
583+
severity=ir.IssueSeverity.WARNING,
584+
translation_key=reason,
585+
translation_placeholders=placeholders,
586+
)
587+
588+
async def async_will_remove_from_hass(self) -> None:
589+
"""Handle when entity will be removed from Home Assistant."""
590+
await super().async_will_remove_from_hass()
591+
592+
if issue_key := DEPRECATED_SENSORS.get(self.entity_description.key):
593+
ir.async_delete_issue(self.hass, DOMAIN, f"{issue_key}_{self.entity_id}")

homeassistant/components/apcupsd/strings.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,5 +241,19 @@
241241
"cannot_connect": {
242242
"message": "Cannot connect to APC UPS Daemon."
243243
}
244+
},
245+
"issues": {
246+
"apc_deprecated": {
247+
"description": "The {entity_name} sensor (`{entity_id}`) is deprecated because it exposes internal details of the APC UPS Daemon response.\n\nIt is still referenced in the following automations or scripts:\n{items}\n\nUpdate those automations or scripts to use supported APC UPS entities instead. Reload the APC UPS Daemon integration afterwards to resolve this issue.",
248+
"title": "{entity_name} sensor is deprecated"
249+
},
250+
"available_via_device_info": {
251+
"description": "The {entity_name} sensor (`{entity_id}`) is deprecated because the same value is available from the device registry via `device_attr(\"{device_id}\", \"{available_via_device_attr}\")`.\n\nIt is still referenced in the following automations or scripts:\n{items}\n\nUpdate those automations or scripts to use the `device_attr` helper instead of this sensor. Reload the APC UPS Daemon integration afterwards to resolve this issue.",
252+
"title": "{entity_name} sensor is deprecated"
253+
},
254+
"date_deprecated": {
255+
"description": "The {entity_name} sensor (`{entity_id}`) is deprecated because the timestamp is already available from other APC UPS sensors via their last updated time.\n\nIt is still referenced in the following automations or scripts:\n{items}\n\nUpdate those automations or scripts to reference any entity's `last_updated` attribute instead (for example, `states.binary_sensor.apcups_online_status.last_updated`). Reload the APC UPS Daemon integration afterwards to resolve this issue.",
256+
"title": "{entity_name} sensor is deprecated"
257+
}
244258
}
245259
}

tests/components/apcupsd/snapshots/test_sensor.ambr

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,244 @@
11
# serializer version: 1
2+
# name: test_deprecated_sensor_issue[apc-apc_deprecated]
3+
IssueRegistryItemSnapshot({
4+
'active': True,
5+
'breaks_in_ha_version': '2026.6.0',
6+
'created': <ANY>,
7+
'data': None,
8+
'dismissed_version': None,
9+
'domain': 'apcupsd',
10+
'is_fixable': False,
11+
'is_persistent': False,
12+
'issue_domain': None,
13+
'issue_id': 'apc_deprecated_sensor.myups_status_data',
14+
'learn_more_url': None,
15+
'severity': <IssueSeverity.WARNING: 'warning'>,
16+
'translation_key': 'apc_deprecated',
17+
'translation_placeholders': dict({
18+
'device_id': '<ANY>',
19+
'entity_id': 'sensor.myups_status_data',
20+
'entity_name': 'Status data',
21+
'items': '''
22+
- [APC UPS automation (apc)](/config/automation/edit/apcupsd_auto_apc)
23+
- [APC UPS script (apc)](/config/script/edit/apcupsd_script_apc)
24+
''',
25+
}),
26+
})
27+
# ---
28+
# name: test_deprecated_sensor_issue[apcmodel-available_via_device_info]
29+
IssueRegistryItemSnapshot({
30+
'active': True,
31+
'breaks_in_ha_version': '2026.6.0',
32+
'created': <ANY>,
33+
'data': None,
34+
'dismissed_version': None,
35+
'domain': 'apcupsd',
36+
'is_fixable': False,
37+
'is_persistent': False,
38+
'issue_domain': None,
39+
'issue_id': 'available_via_device_info_sensor.myups_model',
40+
'learn_more_url': None,
41+
'severity': <IssueSeverity.WARNING: 'warning'>,
42+
'translation_key': 'available_via_device_info',
43+
'translation_placeholders': dict({
44+
'available_via_device_attr': 'model',
45+
'device_id': '<ANY>',
46+
'entity_id': 'sensor.myups_model',
47+
'entity_name': 'Model',
48+
'items': '''
49+
- [APC UPS automation (apcmodel)](/config/automation/edit/apcupsd_auto_apcmodel)
50+
- [APC UPS script (apcmodel)](/config/script/edit/apcupsd_script_apcmodel)
51+
''',
52+
}),
53+
})
54+
# ---
55+
# name: test_deprecated_sensor_issue[date-date_deprecated]
56+
IssueRegistryItemSnapshot({
57+
'active': True,
58+
'breaks_in_ha_version': '2026.6.0',
59+
'created': <ANY>,
60+
'data': None,
61+
'dismissed_version': None,
62+
'domain': 'apcupsd',
63+
'is_fixable': False,
64+
'is_persistent': False,
65+
'issue_domain': None,
66+
'issue_id': 'date_deprecated_sensor.myups_status_date',
67+
'learn_more_url': None,
68+
'severity': <IssueSeverity.WARNING: 'warning'>,
69+
'translation_key': 'date_deprecated',
70+
'translation_placeholders': dict({
71+
'device_id': '<ANY>',
72+
'entity_id': 'sensor.myups_status_date',
73+
'entity_name': 'Status date',
74+
'items': '''
75+
- [APC UPS automation (date)](/config/automation/edit/apcupsd_auto_date)
76+
- [APC UPS script (date)](/config/script/edit/apcupsd_script_date)
77+
''',
78+
}),
79+
})
80+
# ---
81+
# name: test_deprecated_sensor_issue[end apc-date_deprecated]
82+
IssueRegistryItemSnapshot({
83+
'active': True,
84+
'breaks_in_ha_version': '2026.6.0',
85+
'created': <ANY>,
86+
'data': None,
87+
'dismissed_version': None,
88+
'domain': 'apcupsd',
89+
'is_fixable': False,
90+
'is_persistent': False,
91+
'issue_domain': None,
92+
'issue_id': 'date_deprecated_sensor.myups_date_and_time',
93+
'learn_more_url': None,
94+
'severity': <IssueSeverity.WARNING: 'warning'>,
95+
'translation_key': 'date_deprecated',
96+
'translation_placeholders': dict({
97+
'device_id': '<ANY>',
98+
'entity_id': 'sensor.myups_date_and_time',
99+
'entity_name': 'Date and time',
100+
'items': '''
101+
- [APC UPS automation (end apc)](/config/automation/edit/apcupsd_auto_end_apc)
102+
- [APC UPS script (end apc)](/config/script/edit/apcupsd_script_end_apc)
103+
''',
104+
}),
105+
})
106+
# ---
107+
# name: test_deprecated_sensor_issue[firmware-available_via_device_info]
108+
IssueRegistryItemSnapshot({
109+
'active': True,
110+
'breaks_in_ha_version': '2026.6.0',
111+
'created': <ANY>,
112+
'data': None,
113+
'dismissed_version': None,
114+
'domain': 'apcupsd',
115+
'is_fixable': False,
116+
'is_persistent': False,
117+
'issue_domain': None,
118+
'issue_id': 'available_via_device_info_sensor.myups_firmware_version',
119+
'learn_more_url': None,
120+
'severity': <IssueSeverity.WARNING: 'warning'>,
121+
'translation_key': 'available_via_device_info',
122+
'translation_placeholders': dict({
123+
'available_via_device_attr': 'hw_version',
124+
'device_id': '<ANY>',
125+
'entity_id': 'sensor.myups_firmware_version',
126+
'entity_name': 'Firmware version',
127+
'items': '''
128+
- [APC UPS automation (firmware)](/config/automation/edit/apcupsd_auto_firmware)
129+
- [APC UPS script (firmware)](/config/script/edit/apcupsd_script_firmware)
130+
''',
131+
}),
132+
})
133+
# ---
134+
# name: test_deprecated_sensor_issue[model-available_via_device_info]
135+
IssueRegistryItemSnapshot({
136+
'active': True,
137+
'breaks_in_ha_version': '2026.6.0',
138+
'created': <ANY>,
139+
'data': None,
140+
'dismissed_version': None,
141+
'domain': 'apcupsd',
142+
'is_fixable': False,
143+
'is_persistent': False,
144+
'issue_domain': None,
145+
'issue_id': 'available_via_device_info_sensor.myups_model_2',
146+
'learn_more_url': None,
147+
'severity': <IssueSeverity.WARNING: 'warning'>,
148+
'translation_key': 'available_via_device_info',
149+
'translation_placeholders': dict({
150+
'available_via_device_attr': 'model',
151+
'device_id': '<ANY>',
152+
'entity_id': 'sensor.myups_model_2',
153+
'entity_name': 'Model',
154+
'items': '''
155+
- [APC UPS automation (model)](/config/automation/edit/apcupsd_auto_model)
156+
- [APC UPS script (model)](/config/script/edit/apcupsd_script_model)
157+
''',
158+
}),
159+
})
160+
# ---
161+
# name: test_deprecated_sensor_issue[serialno-available_via_device_info]
162+
IssueRegistryItemSnapshot({
163+
'active': True,
164+
'breaks_in_ha_version': '2026.6.0',
165+
'created': <ANY>,
166+
'data': None,
167+
'dismissed_version': None,
168+
'domain': 'apcupsd',
169+
'is_fixable': False,
170+
'is_persistent': False,
171+
'issue_domain': None,
172+
'issue_id': 'available_via_device_info_sensor.myups_serial_number',
173+
'learn_more_url': None,
174+
'severity': <IssueSeverity.WARNING: 'warning'>,
175+
'translation_key': 'available_via_device_info',
176+
'translation_placeholders': dict({
177+
'available_via_device_attr': 'serial_number',
178+
'device_id': '<ANY>',
179+
'entity_id': 'sensor.myups_serial_number',
180+
'entity_name': 'Serial number',
181+
'items': '''
182+
- [APC UPS automation (serialno)](/config/automation/edit/apcupsd_auto_serialno)
183+
- [APC UPS script (serialno)](/config/script/edit/apcupsd_script_serialno)
184+
''',
185+
}),
186+
})
187+
# ---
188+
# name: test_deprecated_sensor_issue[upsname-available_via_device_info]
189+
IssueRegistryItemSnapshot({
190+
'active': True,
191+
'breaks_in_ha_version': '2026.6.0',
192+
'created': <ANY>,
193+
'data': None,
194+
'dismissed_version': None,
195+
'domain': 'apcupsd',
196+
'is_fixable': False,
197+
'is_persistent': False,
198+
'issue_domain': None,
199+
'issue_id': 'available_via_device_info_sensor.myups_name',
200+
'learn_more_url': None,
201+
'severity': <IssueSeverity.WARNING: 'warning'>,
202+
'translation_key': 'available_via_device_info',
203+
'translation_placeholders': dict({
204+
'available_via_device_attr': 'name',
205+
'device_id': '<ANY>',
206+
'entity_id': 'sensor.myups_name',
207+
'entity_name': 'Name',
208+
'items': '''
209+
- [APC UPS automation (upsname)](/config/automation/edit/apcupsd_auto_upsname)
210+
- [APC UPS script (upsname)](/config/script/edit/apcupsd_script_upsname)
211+
''',
212+
}),
213+
})
214+
# ---
215+
# name: test_deprecated_sensor_issue[version-available_via_device_info]
216+
IssueRegistryItemSnapshot({
217+
'active': True,
218+
'breaks_in_ha_version': '2026.6.0',
219+
'created': <ANY>,
220+
'data': None,
221+
'dismissed_version': None,
222+
'domain': 'apcupsd',
223+
'is_fixable': False,
224+
'is_persistent': False,
225+
'issue_domain': None,
226+
'issue_id': 'available_via_device_info_sensor.myups_daemon_version',
227+
'learn_more_url': None,
228+
'severity': <IssueSeverity.WARNING: 'warning'>,
229+
'translation_key': 'available_via_device_info',
230+
'translation_placeholders': dict({
231+
'available_via_device_attr': 'sw_version',
232+
'device_id': '<ANY>',
233+
'entity_id': 'sensor.myups_daemon_version',
234+
'entity_name': 'Daemon version',
235+
'items': '''
236+
- [APC UPS automation (version)](/config/automation/edit/apcupsd_auto_version)
237+
- [APC UPS script (version)](/config/script/edit/apcupsd_script_version)
238+
''',
239+
}),
240+
})
241+
# ---
2242
# name: test_sensor[sensor.myups_alarm_delay-entry]
3243
EntityRegistryEntrySnapshot({
4244
'aliases': set({

0 commit comments

Comments
 (0)