Add ambient temperature and humidity status sensors to NUT (#124181)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
tdfountain 2025-02-24 06:09:43 -08:00 committed by GitHub
parent 5025e31129
commit 51a881f3b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 724 additions and 9 deletions

4
CODEOWNERS generated
View File

@ -1051,8 +1051,8 @@ build.json @home-assistant/supervisor
/tests/components/numato/ @clssn
/homeassistant/components/number/ @home-assistant/core @Shulyaka
/tests/components/number/ @home-assistant/core @Shulyaka
/homeassistant/components/nut/ @bdraco @ollo69 @pestevez
/tests/components/nut/ @bdraco @ollo69 @pestevez
/homeassistant/components/nut/ @bdraco @ollo69 @pestevez @tdfountain
/tests/components/nut/ @bdraco @ollo69 @pestevez @tdfountain
/homeassistant/components/nws/ @MatthewFlamm @kamiyo
/tests/components/nws/ @MatthewFlamm @kamiyo
/homeassistant/components/nyt_games/ @joostlek

View File

@ -39,8 +39,8 @@ async def async_get_config_entry_diagnostics(
hass_device = device_registry.async_get_device(
identifiers={(DOMAIN, hass_data.unique_id)}
)
if not hass_device:
return data
# Device is always created
assert hass_device is not None
data["device"] = {
**attr.asdict(hass_device),

View File

@ -1,6 +1,12 @@
{
"entity": {
"sensor": {
"ambient_humidity_status": {
"default": "mdi:information-outline"
},
"ambient_temperature_status": {
"default": "mdi:information-outline"
},
"battery_alarm_threshold": {
"default": "mdi:information-outline"
},

View File

@ -1,7 +1,7 @@
{
"domain": "nut",
"name": "Network UPS Tools (NUT)",
"codeowners": ["@bdraco", "@ollo69", "@pestevez"],
"codeowners": ["@bdraco", "@ollo69", "@pestevez", "@tdfountain"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/nut",
"integration_type": "device",

View File

@ -46,8 +46,17 @@ NUT_DEV_INFO_TO_DEV_INFO: dict[str, str] = {
"serial": ATTR_SERIAL_NUMBER,
}
AMBIENT_THRESHOLD_STATUS_OPTIONS = [
"good",
"warning-low",
"critical-low",
"warning-high",
"critical-high",
]
_LOGGER = logging.getLogger(__name__)
SENSOR_TYPES: Final[dict[str, SensorEntityDescription]] = {
"ups.status.display": SensorEntityDescription(
key="ups.status.display",
@ -930,6 +939,13 @@ SENSOR_TYPES: Final[dict[str, SensorEntityDescription]] = {
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
"ambient.humidity.status": SensorEntityDescription(
key="ambient.humidity.status",
translation_key="ambient_humidity_status",
device_class=SensorDeviceClass.ENUM,
options=AMBIENT_THRESHOLD_STATUS_OPTIONS,
entity_category=EntityCategory.DIAGNOSTIC,
),
"ambient.temperature": SensorEntityDescription(
key="ambient.temperature",
translation_key="ambient_temperature",
@ -938,6 +954,13 @@ SENSOR_TYPES: Final[dict[str, SensorEntityDescription]] = {
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
"ambient.temperature.status": SensorEntityDescription(
key="ambient.temperature.status",
translation_key="ambient_temperature_status",
device_class=SensorDeviceClass.ENUM,
options=AMBIENT_THRESHOLD_STATUS_OPTIONS,
entity_category=EntityCategory.DIAGNOSTIC,
),
"watts": SensorEntityDescription(
key="watts",
translation_key="watts",

View File

@ -80,7 +80,9 @@
"entity": {
"sensor": {
"ambient_humidity": { "name": "Ambient humidity" },
"ambient_humidity_status": { "name": "Ambient humidity status" },
"ambient_temperature": { "name": "Ambient temperature" },
"ambient_temperature_status": { "name": "Ambient temperature status" },
"battery_alarm_threshold": { "name": "Battery alarm threshold" },
"battery_capacity": { "name": "Battery capacity" },
"battery_charge": { "name": "Battery charge" },

View File

@ -0,0 +1,5 @@
"""NUT session fixtures."""
import pytest
pytest.register_assert_rewrite("tests.components.nut.util")

View File

@ -0,0 +1,539 @@
{
"ambient.contacts.1.status": "opened",
"ambient.contacts.2.status": "opened",
"ambient.count": "0",
"ambient.humidity": "29.90",
"ambient.humidity.high": "90",
"ambient.humidity.high.critical": "90",
"ambient.humidity.high.warning": "65",
"ambient.humidity.low": "10",
"ambient.humidity.low.critical": "10",
"ambient.humidity.low.warning": "20",
"ambient.humidity.status": "good",
"ambient.present": "yes",
"ambient.temperature": "28.9",
"ambient.temperature.high": "43.30",
"ambient.temperature.high.critical": "43.30",
"ambient.temperature.high.warning": "37.70",
"ambient.temperature.low": "5",
"ambient.temperature.low.critical": "5",
"ambient.temperature.low.warning": "10",
"ambient.temperature.status": "good",
"device.contact": "Contact Name",
"device.count": "1",
"device.description": "ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE",
"device.location": "Device Location",
"device.macaddr": "00 00 00 FF FF FF ",
"device.mfr": "EATON",
"device.model": "ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE",
"device.part": "EMA000-00",
"device.serial": "A000A00000",
"device.type": "pdu",
"driver.debug": "0",
"driver.flag.allow_killpower": "0",
"driver.name": "snmp-ups",
"driver.parameter.pollinterval": "2",
"driver.parameter.port": "eaton-pdu",
"driver.parameter.synchronous": "auto",
"driver.state": "dumping",
"driver.version": "2.8.2.882-882-g63d90ebcb",
"driver.version.data": "eaton_epdu MIB 0.69",
"driver.version.internal": "1.31",
"input.current": "4.30",
"input.current.high.critical": "16",
"input.current.high.warning": "12.80",
"input.current.low.warning": "0",
"input.current.nominal": "16",
"input.current.status": "good",
"input.feed.color": "0",
"input.feed.desc": "Feed A",
"input.frequency": "60",
"input.frequency.status": "good",
"input.L1.current": "4.30",
"input.L1.current.high.critical": "16",
"input.L1.current.high.warning": "12.80",
"input.L1.current.low.warning": "0",
"input.L1.current.nominal": "16",
"input.L1.current.status": "good",
"input.L1.load": "26",
"input.L1.power": "529",
"input.L1.realpower": "482",
"input.L1.voltage": "122.91",
"input.L1.voltage.high.critical": "140",
"input.L1.voltage.high.warning": "130",
"input.L1.voltage.low.critical": "90",
"input.L1.voltage.low.warning": "95",
"input.L1.voltage.status": "good",
"input.load": "26",
"input.phases": "1",
"input.power": "532",
"input.realpower": "482",
"input.realpower.nominal": "1920",
"input.voltage": "122.91",
"input.voltage.high.critical": "140",
"input.voltage.high.warning": "130",
"input.voltage.low.critical": "90",
"input.voltage.low.warning": "95",
"input.voltage.status": "good",
"outlet.1.current": "0",
"outlet.1.current.high.critical": "16",
"outlet.1.current.high.warning": "12.80",
"outlet.1.current.low.warning": "0",
"outlet.1.current.status": "good",
"outlet.1.delay.shutdown": "120",
"outlet.1.delay.start": "1",
"outlet.1.desc": "Outlet A1",
"outlet.1.groupid": "1",
"outlet.1.id": "1",
"outlet.1.name": "A1",
"outlet.1.power": "0",
"outlet.1.realpower": "0",
"outlet.1.status": "on",
"outlet.1.switchable": "yes",
"outlet.1.timer.shutdown": "-1",
"outlet.1.timer.start": "-1",
"outlet.1.type": "nema520",
"outlet.10.current": "0.26",
"outlet.10.current.high.critical": "16",
"outlet.10.current.high.warning": "12.80",
"outlet.10.current.low.warning": "0",
"outlet.10.current.status": "good",
"outlet.10.delay.shutdown": "120",
"outlet.10.delay.start": "10",
"outlet.10.desc": "Outlet A10",
"outlet.10.groupid": "1",
"outlet.10.id": "10",
"outlet.10.name": "A10",
"outlet.10.power": "32",
"outlet.10.realpower": "15",
"outlet.10.status": "on",
"outlet.10.switchable": "yes",
"outlet.10.timer.shutdown": "-1",
"outlet.10.timer.start": "-1",
"outlet.10.type": "nema520",
"outlet.11.current": "0.24",
"outlet.11.current.high.critical": "16",
"outlet.11.current.high.warning": "12.80",
"outlet.11.current.low.warning": "0",
"outlet.11.current.status": "good",
"outlet.11.delay.shutdown": "120",
"outlet.11.delay.start": "11",
"outlet.11.desc": "Outlet A11",
"outlet.11.groupid": "1",
"outlet.11.id": "11",
"outlet.11.name": "A11",
"outlet.11.power": "29",
"outlet.11.realpower": "22",
"outlet.11.status": "on",
"outlet.11.switchable": "yes",
"outlet.11.timer.shutdown": "-1",
"outlet.11.timer.start": "-1",
"outlet.11.type": "nema520",
"outlet.12.current": "0",
"outlet.12.current.high.critical": "16",
"outlet.12.current.high.warning": "12.80",
"outlet.12.current.low.warning": "0",
"outlet.12.current.status": "good",
"outlet.12.delay.shutdown": "120",
"outlet.12.delay.start": "12",
"outlet.12.desc": "Outlet A12",
"outlet.12.groupid": "1",
"outlet.12.id": "12",
"outlet.12.name": "A12",
"outlet.12.power": "0",
"outlet.12.realpower": "0",
"outlet.12.status": "on",
"outlet.12.switchable": "yes",
"outlet.12.timer.shutdown": "-1",
"outlet.12.timer.start": "-1",
"outlet.12.type": "nema520",
"outlet.13.current": "0.23",
"outlet.13.current.high.critical": "16",
"outlet.13.current.high.warning": "12.80",
"outlet.13.current.low.warning": "0",
"outlet.13.current.status": "good",
"outlet.13.delay.shutdown": "0",
"outlet.13.delay.start": "0",
"outlet.13.desc": "Outlet A13",
"outlet.13.groupid": "1",
"outlet.13.id": "0",
"outlet.13.name": "A13",
"outlet.13.power": "27",
"outlet.13.realpower": "9",
"outlet.13.status": "on",
"outlet.13.switchable": "yes",
"outlet.13.timer.shutdown": "-1",
"outlet.13.timer.start": "-1",
"outlet.13.type": "nema520",
"outlet.14.current": "0.10",
"outlet.14.current.high.critical": "16",
"outlet.14.current.high.warning": "12.80",
"outlet.14.current.low.warning": "0",
"outlet.14.current.status": "good",
"outlet.14.delay.shutdown": "120",
"outlet.14.delay.start": "14",
"outlet.14.desc": "Outlet A14",
"outlet.14.groupid": "1",
"outlet.14.id": "14",
"outlet.14.name": "A14",
"outlet.14.power": "12",
"outlet.14.realpower": "7",
"outlet.14.status": "on",
"outlet.14.switchable": "yes",
"outlet.14.timer.shutdown": "-1",
"outlet.14.timer.start": "-1",
"outlet.14.type": "nema520",
"outlet.15.current": "0.03",
"outlet.15.current.high.critical": "16",
"outlet.15.current.high.warning": "12.80",
"outlet.15.current.low.warning": "0",
"outlet.15.current.status": "good",
"outlet.15.delay.shutdown": "120",
"outlet.15.delay.start": "15",
"outlet.15.desc": "Outlet A15",
"outlet.15.groupid": "1",
"outlet.15.id": "15",
"outlet.15.name": "A15",
"outlet.15.power": "3",
"outlet.15.realpower": "1",
"outlet.15.status": "on",
"outlet.15.switchable": "yes",
"outlet.15.timer.shutdown": "-1",
"outlet.15.timer.start": "-1",
"outlet.15.type": "nema520",
"outlet.16.current": "0.04",
"outlet.16.current.high.critical": "16",
"outlet.16.current.high.warning": "12.80",
"outlet.16.current.low.warning": "0",
"outlet.16.current.status": "good",
"outlet.16.delay.shutdown": "120",
"outlet.16.delay.start": "16",
"outlet.16.desc": "Outlet A16",
"outlet.16.groupid": "1",
"outlet.16.id": "16",
"outlet.16.name": "A16",
"outlet.16.power": "4",
"outlet.16.realpower": "1",
"outlet.16.status": "on",
"outlet.16.switchable": "yes",
"outlet.16.timer.shutdown": "-1",
"outlet.16.timer.start": "-1",
"outlet.16.type": "nema520",
"outlet.17.current": "0.19",
"outlet.17.current.high.critical": "16",
"outlet.17.current.high.warning": "12.80",
"outlet.17.current.low.warning": "0",
"outlet.17.current.status": "good",
"outlet.17.delay.shutdown": "0",
"outlet.17.delay.start": "0",
"outlet.17.desc": "Outlet A17",
"outlet.17.groupid": "1",
"outlet.17.id": "0",
"outlet.17.name": "A17",
"outlet.17.power": "23",
"outlet.17.realpower": "5",
"outlet.17.status": "on",
"outlet.17.switchable": "yes",
"outlet.17.timer.shutdown": "-1",
"outlet.17.timer.start": "-1",
"outlet.17.type": "nema520",
"outlet.18.current": "0.35",
"outlet.18.current.high.critical": "16",
"outlet.18.current.high.warning": "12.80",
"outlet.18.current.low.warning": "0",
"outlet.18.current.status": "good",
"outlet.18.delay.shutdown": "0",
"outlet.18.delay.start": "0",
"outlet.18.desc": "Outlet A18",
"outlet.18.groupid": "1",
"outlet.18.id": "0",
"outlet.18.name": "A18",
"outlet.18.power": "42",
"outlet.18.realpower": "34",
"outlet.18.status": "on",
"outlet.18.switchable": "yes",
"outlet.18.timer.shutdown": "-1",
"outlet.18.timer.start": "-1",
"outlet.18.type": "nema520",
"outlet.19.current": "0.12",
"outlet.19.current.high.critical": "16",
"outlet.19.current.high.warning": "12.80",
"outlet.19.current.low.warning": "0",
"outlet.19.current.status": "good",
"outlet.19.delay.shutdown": "0",
"outlet.19.delay.start": "0",
"outlet.19.desc": "Outlet A19",
"outlet.19.groupid": "1",
"outlet.19.id": "0",
"outlet.19.name": "A19",
"outlet.19.power": "15",
"outlet.19.realpower": "6",
"outlet.19.status": "on",
"outlet.19.switchable": "yes",
"outlet.19.timer.shutdown": "-1",
"outlet.19.timer.start": "-1",
"outlet.19.type": "nema520",
"outlet.2.current": "0.39",
"outlet.2.current.high.critical": "16",
"outlet.2.current.high.warning": "12.80",
"outlet.2.current.low.warning": "0",
"outlet.2.current.status": "good",
"outlet.2.delay.shutdown": "120",
"outlet.2.delay.start": "2",
"outlet.2.desc": "Outlet A2",
"outlet.2.groupid": "1",
"outlet.2.id": "2",
"outlet.2.name": "A2",
"outlet.2.power": "47",
"outlet.2.realpower": "43",
"outlet.2.status": "on",
"outlet.2.switchable": "yes",
"outlet.2.timer.shutdown": "-1",
"outlet.2.timer.start": "-1",
"outlet.2.type": "nema520",
"outlet.20.current": "0",
"outlet.20.current.high.critical": "16",
"outlet.20.current.high.warning": "12.80",
"outlet.20.current.low.warning": "0",
"outlet.20.current.status": "good",
"outlet.20.delay.shutdown": "120",
"outlet.20.delay.start": "20",
"outlet.20.desc": "Outlet A20",
"outlet.20.groupid": "1",
"outlet.20.id": "20",
"outlet.20.name": "A20",
"outlet.20.power": "0",
"outlet.20.realpower": "0",
"outlet.20.status": "on",
"outlet.20.switchable": "yes",
"outlet.20.timer.shutdown": "-1",
"outlet.20.timer.start": "-1",
"outlet.20.type": "nema520",
"outlet.21.current": "0",
"outlet.21.current.high.critical": "16",
"outlet.21.current.high.warning": "12.80",
"outlet.21.current.low.warning": "0",
"outlet.21.current.status": "good",
"outlet.21.delay.shutdown": "120",
"outlet.21.delay.start": "21",
"outlet.21.desc": "Outlet A21",
"outlet.21.groupid": "1",
"outlet.21.id": "21",
"outlet.21.name": "A21",
"outlet.21.power": "0",
"outlet.21.realpower": "0",
"outlet.21.status": "on",
"outlet.21.switchable": "yes",
"outlet.21.timer.shutdown": "-1",
"outlet.21.timer.start": "-1",
"outlet.21.type": "nema520",
"outlet.22.current": "0",
"outlet.22.current.high.critical": "16",
"outlet.22.current.high.warning": "12.80",
"outlet.22.current.low.warning": "0",
"outlet.22.current.status": "good",
"outlet.22.delay.shutdown": "0",
"outlet.22.delay.start": "0",
"outlet.22.desc": "Outlet A22",
"outlet.22.groupid": "1",
"outlet.22.id": "0",
"outlet.22.name": "A22",
"outlet.22.power": "0",
"outlet.22.realpower": "0",
"outlet.22.status": "on",
"outlet.22.switchable": "yes",
"outlet.22.timer.shutdown": "-1",
"outlet.22.timer.start": "-1",
"outlet.22.type": "nema520",
"outlet.23.current": "0.34",
"outlet.23.current.high.critical": "16",
"outlet.23.current.high.warning": "12.80",
"outlet.23.current.low.warning": "0",
"outlet.23.current.status": "good",
"outlet.23.delay.shutdown": "120",
"outlet.23.delay.start": "23",
"outlet.23.desc": "Outlet A23",
"outlet.23.groupid": "1",
"outlet.23.id": "23",
"outlet.23.name": "A23",
"outlet.23.power": "41",
"outlet.23.realpower": "39",
"outlet.23.status": "on",
"outlet.23.switchable": "yes",
"outlet.23.timer.shutdown": "-1",
"outlet.23.timer.start": "-1",
"outlet.23.type": "nema520",
"outlet.24.current": "0.19",
"outlet.24.current.high.critical": "16",
"outlet.24.current.high.warning": "12.80",
"outlet.24.current.low.warning": "0",
"outlet.24.current.status": "good",
"outlet.24.delay.shutdown": "0",
"outlet.24.delay.start": "0",
"outlet.24.desc": "Outlet A24",
"outlet.24.groupid": "1",
"outlet.24.id": "0",
"outlet.24.name": "A24",
"outlet.24.power": "23",
"outlet.24.realpower": "11",
"outlet.24.status": "on",
"outlet.24.switchable": "yes",
"outlet.24.timer.shutdown": "-1",
"outlet.24.timer.start": "-1",
"outlet.24.type": "nema520",
"outlet.3.current": "0.46",
"outlet.3.current.high.critical": "16",
"outlet.3.current.high.warning": "12.80",
"outlet.3.current.low.warning": "0",
"outlet.3.current.status": "good",
"outlet.3.delay.shutdown": "120",
"outlet.3.delay.start": "3",
"outlet.3.desc": "Outlet A3",
"outlet.3.groupid": "1",
"outlet.3.id": "3",
"outlet.3.name": "A3",
"outlet.3.power": "56",
"outlet.3.realpower": "53",
"outlet.3.status": "on",
"outlet.3.switchable": "yes",
"outlet.3.timer.shutdown": "-1",
"outlet.3.timer.start": "-1",
"outlet.3.type": "nema520",
"outlet.4.current": "0.44",
"outlet.4.current.high.critical": "16",
"outlet.4.current.high.warning": "12.80",
"outlet.4.current.low.warning": "0",
"outlet.4.current.status": "good",
"outlet.4.delay.shutdown": "120",
"outlet.4.delay.start": "4",
"outlet.4.desc": "Outlet A4",
"outlet.4.groupid": "1",
"outlet.4.id": "4",
"outlet.4.name": "A4",
"outlet.4.power": "53",
"outlet.4.realpower": "48",
"outlet.4.status": "on",
"outlet.4.switchable": "yes",
"outlet.4.timer.shutdown": "-1",
"outlet.4.timer.start": "-1",
"outlet.4.type": "nema520",
"outlet.5.current": "0.43",
"outlet.5.current.high.critical": "16",
"outlet.5.current.high.warning": "12.80",
"outlet.5.current.low.warning": "0",
"outlet.5.current.status": "good",
"outlet.5.delay.shutdown": "120",
"outlet.5.delay.start": "5",
"outlet.5.desc": "Outlet A5",
"outlet.5.groupid": "1",
"outlet.5.id": "5",
"outlet.5.name": "A5",
"outlet.5.power": "52",
"outlet.5.realpower": "48",
"outlet.5.status": "on",
"outlet.5.switchable": "yes",
"outlet.5.timer.shutdown": "-1",
"outlet.5.timer.start": "-1",
"outlet.5.type": "nema520",
"outlet.6.current": "1.07",
"outlet.6.current.high.critical": "16",
"outlet.6.current.high.warning": "12.80",
"outlet.6.current.low.warning": "0",
"outlet.6.current.status": "good",
"outlet.6.delay.shutdown": "120",
"outlet.6.delay.start": "6",
"outlet.6.desc": "Outlet A6",
"outlet.6.groupid": "1",
"outlet.6.id": "6",
"outlet.6.name": "A6",
"outlet.6.power": "131",
"outlet.6.realpower": "118",
"outlet.6.status": "on",
"outlet.6.switchable": "yes",
"outlet.6.timer.shutdown": "-1",
"outlet.6.timer.start": "-1",
"outlet.6.type": "nema520",
"outlet.7.current": "0",
"outlet.7.current.high.critical": "16",
"outlet.7.current.high.warning": "12.80",
"outlet.7.current.low.warning": "0",
"outlet.7.current.status": "good",
"outlet.7.delay.shutdown": "120",
"outlet.7.delay.start": "7",
"outlet.7.desc": "Outlet A7",
"outlet.7.groupid": "1",
"outlet.7.id": "7",
"outlet.7.name": "A7",
"outlet.7.power": "0",
"outlet.7.realpower": "0",
"outlet.7.status": "on",
"outlet.7.switchable": "yes",
"outlet.7.timer.shutdown": "-1",
"outlet.7.timer.start": "-1",
"outlet.7.type": "nema520",
"outlet.8.current": "0",
"outlet.8.current.high.critical": "16",
"outlet.8.current.high.warning": "12.80",
"outlet.8.current.low.warning": "0",
"outlet.8.current.status": "good",
"outlet.8.delay.shutdown": "120",
"outlet.8.delay.start": "8",
"outlet.8.desc": "Outlet A8",
"outlet.8.groupid": "1",
"outlet.8.id": "8",
"outlet.8.name": "A8",
"outlet.8.power": "0",
"outlet.8.realpower": "0",
"outlet.8.status": "on",
"outlet.8.switchable": "yes",
"outlet.8.timer.shutdown": "-1",
"outlet.8.timer.start": "-1",
"outlet.8.type": "nema520",
"outlet.9.current": "0",
"outlet.9.current.high.critical": "16",
"outlet.9.current.high.warning": "12.80",
"outlet.9.current.low.warning": "0",
"outlet.9.current.status": "good",
"outlet.9.delay.shutdown": "120",
"outlet.9.delay.start": "9",
"outlet.9.desc": "Outlet A9",
"outlet.9.groupid": "1",
"outlet.9.id": "9",
"outlet.9.name": "A9",
"outlet.9.power": "0",
"outlet.9.realpower": "0",
"outlet.9.status": "on",
"outlet.9.switchable": "yes",
"outlet.9.timer.shutdown": "-1",
"outlet.9.timer.start": "-1",
"outlet.9.type": "nema520",
"outlet.count": "24",
"outlet.current": "43.05",
"outlet.desc": "All outlets",
"outlet.frequency": "60",
"outlet.group.1.color": "16051527",
"outlet.group.1.count": "24",
"outlet.group.1.desc": "Section A",
"outlet.group.1.id": "1",
"outlet.group.1.input": "1",
"outlet.group.1.name": "A",
"outlet.group.1.phase": "1",
"outlet.group.1.status": "on",
"outlet.group.1.type": "outlet-section",
"outlet.group.1.voltage": "122.83",
"outlet.group.1.voltage.high.critical": "140",
"outlet.group.1.voltage.high.warning": "130",
"outlet.group.1.voltage.low.critical": "90",
"outlet.group.1.voltage.low.warning": "95",
"outlet.group.1.voltage.status": "good",
"outlet.group.count": "1",
"outlet.id": "0",
"outlet.switchable": "yes",
"outlet.voltage": "122.91",
"ups.firmware": "05.01.0002",
"ups.mfr": "EATON",
"ups.model": "ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE",
"ups.serial": "A000A00000",
"ups.status": "",
"ups.type": "pdu"
}

View File

@ -1,12 +1,19 @@
"""Test init of Nut integration."""
from copy import deepcopy
from unittest.mock import patch
from aionut import NUTError, NUTLoginError
from homeassistant.components.nut.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_UNAVAILABLE
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_USERNAME,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
@ -147,3 +154,44 @@ async def test_device_location(hass: HomeAssistant) -> None:
assert device_entry is not None
assert device_entry.suggested_area == mock_device_location
async def test_update_options(hass: HomeAssistant) -> None:
"""Test update options triggers reload."""
mock_pynut = _get_mock_nutclient(
list_ups={"ups1": "UPS 1"}, list_vars={"ups.status": "OL"}
)
with patch(
"homeassistant.components.nut.AIONUTClient",
return_value=mock_pynut,
):
mock_config_entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_HOST: "mock",
CONF_PASSWORD: "somepassword",
CONF_PORT: "mock",
CONF_USERNAME: "someuser",
},
options={
"device_options": {
"fake_option": "fake_option_value",
},
},
)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert mock_config_entry.state is ConfigEntryState.LOADED
new_options = deepcopy(dict(mock_config_entry.options))
new_options["device_options"].clear()
hass.config_entries.async_update_entry(mock_config_entry, options=new_options)
await hass.async_block_till_done()
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert mock_config_entry.state is ConfigEntryState.LOADED

View File

@ -5,17 +5,23 @@ from unittest.mock import patch
import pytest
from homeassistant.components.nut.const import DOMAIN
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
CONF_RESOURCES,
PERCENTAGE,
STATE_UNKNOWN,
UnitOfElectricPotential,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .util import _get_mock_nutclient, async_init_integration
from .util import (
_get_mock_nutclient,
_test_sensor_and_attributes,
async_init_integration,
)
from tests.common import MockConfigEntry
@ -32,7 +38,7 @@ from tests.common import MockConfigEntry
"blazer_usb",
],
)
async def test_devices(
async def test_ups_devices(
hass: HomeAssistant, entity_registry: er.EntityRegistry, model: str
) -> None:
"""Test creation of device sensors."""
@ -67,7 +73,7 @@ async def test_devices(
),
],
)
async def test_devices_with_unique_ids(
async def test_ups_devices_with_unique_ids(
hass: HomeAssistant, entity_registry: er.EntityRegistry, model: str, unique_id: str
) -> None:
"""Test creation of device sensors with unique ids."""
@ -92,6 +98,65 @@ async def test_devices_with_unique_ids(
)
@pytest.mark.parametrize(
("model", "unique_id_base"),
[
(
"EATON-EPDU-G3",
"EATON_ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE_A000A00000_",
),
],
)
async def test_pdu_devices_with_unique_ids(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
model: str,
unique_id_base: str,
) -> None:
"""Test creation of device sensors with unique ids."""
await _test_sensor_and_attributes(
hass,
entity_registry,
model,
unique_id=f"{unique_id_base}input.voltage",
device_id="sensor.ups1_input_voltage",
state_value="122.91",
expected_attributes={
"device_class": SensorDeviceClass.VOLTAGE,
"state_class": SensorStateClass.MEASUREMENT,
"friendly_name": "Ups1 Input voltage",
"unit_of_measurement": UnitOfElectricPotential.VOLT,
},
)
await _test_sensor_and_attributes(
hass,
entity_registry,
model,
unique_id=f"{unique_id_base}ambient.humidity.status",
device_id="sensor.ups1_ambient_humidity_status",
state_value="good",
expected_attributes={
"device_class": SensorDeviceClass.ENUM,
"friendly_name": "Ups1 Ambient humidity status",
},
)
await _test_sensor_and_attributes(
hass,
entity_registry,
model,
unique_id=f"{unique_id_base}ambient.temperature.status",
device_id="sensor.ups1_ambient_temperature_status",
state_value="good",
expected_attributes={
"device_class": SensorDeviceClass.ENUM,
"friendly_name": "Ups1 Ambient temperature status",
},
)
async def test_state_sensors(hass: HomeAssistant) -> None:
"""Test creation of status display sensors."""
entry = MockConfigEntry(

View File

@ -6,6 +6,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
from homeassistant.components.nut.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, load_fixture
@ -79,3 +80,29 @@ async def async_init_integration(
await hass.async_block_till_done()
return entry
async def _test_sensor_and_attributes(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
model: str,
unique_id: str,
device_id: str,
state_value: str,
expected_attributes: dict,
) -> None:
"""Test creation of device sensors with unique ids."""
await async_init_integration(hass, model)
entry = entity_registry.async_get(device_id)
assert entry
assert entry.unique_id == unique_id
state = hass.states.get(device_id)
assert state.state == state_value
# Only test for a subset of attributes in case
# HA changes the implementation and a new one appears
assert all(
state.attributes[key] == attr for key, attr in expected_attributes.items()
)