From 2d4e451837b82a2041f206f3bd3c82d3f8d7eaab Mon Sep 17 00:00:00 2001 From: Raphael Hehl <7577984+RaHehl@users.noreply.github.com> Date: Sun, 23 Aug 2026 19:26:28 +0200 Subject: [PATCH] Add custom IR-filter-only and manual infrared modes to UniFi Protect cameras (#174794) --- .../components/unifiprotect/select.py | 2 + .../components/unifiprotect/strings.json | 4 +- tests/components/unifiprotect/test_select.py | 47 +++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/unifiprotect/select.py b/homeassistant/components/unifiprotect/select.py index 888267d346a5..be4984e35519 100644 --- a/homeassistant/components/unifiprotect/select.py +++ b/homeassistant/components/unifiprotect/select.py @@ -68,6 +68,8 @@ INFRARED_MODES = [ {"id": IRLEDMode.ON.value, "name": "on"}, {"id": IRLEDMode.AUTO_NO_LED.value, "name": "auto_filter_only"}, {"id": IRLEDMode.CUSTOM.value, "name": "custom"}, + {"id": IRLEDMode.CUSTOM_FILTER_ONLY.value, "name": "custom_filter_only"}, + {"id": IRLEDMode.MANUAL.value, "name": "manual"}, {"id": IRLEDMode.OFF.value, "name": "off"}, ] diff --git a/homeassistant/components/unifiprotect/strings.json b/homeassistant/components/unifiprotect/strings.json index 111e0f722ebf..cba086a1ca6a 100644 --- a/homeassistant/components/unifiprotect/strings.json +++ b/homeassistant/components/unifiprotect/strings.json @@ -430,7 +430,9 @@ "state": { "auto": "Auto", "auto_filter_only": "Auto (filter only, no LEDs)", - "custom": "Auto (custom lux)", + "custom": "Custom (IR filter + LEDs)", + "custom_filter_only": "Custom (IR filter only)", + "manual": "Manual", "off": "Always disable", "on": "Always enable" } diff --git a/tests/components/unifiprotect/test_select.py b/tests/components/unifiprotect/test_select.py index bb221d448cee..830b494314d5 100644 --- a/tests/components/unifiprotect/test_select.py +++ b/tests/components/unifiprotect/test_select.py @@ -561,8 +561,49 @@ async def test_select_set_option_camera_recording( mock_method.assert_called_once_with(RecordingMode.NEVER) +@pytest.mark.parametrize( + ("mode", "expected"), + [ + (IRLEDMode.CUSTOM_FILTER_ONLY, "custom_filter_only"), + (IRLEDMode.MANUAL, "manual"), + (IRLEDMode.CUSTOM, "custom"), + ], +) +async def test_select_camera_ir_current_option( + hass: HomeAssistant, + ufp: MockUFPFixture, + doorbell: Camera, + mode: IRLEDMode, + expected: str, +) -> None: + """A camera already in one of these modes reports it as the current option.""" + doorbell.isp_settings.ir_led_mode = mode + + await init_entry(hass, ufp, [doorbell]) + + _, entity_id = await ids_from_device_description( + hass, Platform.SELECT, doorbell, CAMERA_SELECTS[1] + ) + state = hass.states.get(entity_id) + assert state + assert state.state == expected + assert expected in state.attributes[ATTR_OPTIONS] + + +@pytest.mark.parametrize( + ("option", "expected"), + [ + ("on", IRLEDMode.ON), + ("custom_filter_only", IRLEDMode.CUSTOM_FILTER_ONLY), + ("manual", IRLEDMode.MANUAL), + ], +) async def test_select_set_option_camera_ir( - hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera + hass: HomeAssistant, + ufp: MockUFPFixture, + doorbell: Camera, + option: str, + expected: IRLEDMode, ) -> None: """Test Infrared Mode select.""" @@ -579,11 +620,11 @@ async def test_select_set_option_camera_ir( await hass.services.async_call( "select", "select_option", - {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "on"}, + {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: option}, blocking=True, ) - mock_method.assert_called_once_with(IRLEDMode.ON) + mock_method.assert_called_once_with(expected) async def test_select_set_option_camera_doorbell_custom(