From 286763b9985a89edc4865124c973b3322f3166d3 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Fri, 19 Sep 2025 15:22:48 +0200 Subject: [PATCH 1/5] Fix `KeyError` for Shelly Duo Bulb Gen3 (#152612) --- homeassistant/components/shelly/light.py | 9 +++++--- tests/components/shelly/test_light.py | 26 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/shelly/light.py b/homeassistant/components/shelly/light.py index 12ca25916b867b..83e2544c084705 100644 --- a/homeassistant/components/shelly/light.py +++ b/homeassistant/components/shelly/light.py @@ -460,9 +460,12 @@ def __init__( ) -> None: """Initialize light.""" super().__init__(coordinator, key, attribute, description) - color_temp_range = coordinator.device.config[f"cct:{self._id}"]["ct_range"] - self._attr_min_color_temp_kelvin = color_temp_range[0] - self._attr_max_color_temp_kelvin = color_temp_range[1] + if color_temp_range := coordinator.device.config[key].get("ct_range"): + self._attr_min_color_temp_kelvin = color_temp_range[0] + self._attr_max_color_temp_kelvin = color_temp_range[1] + else: + self._attr_min_color_temp_kelvin = KELVIN_MIN_VALUE_WHITE + self._attr_max_color_temp_kelvin = KELVIN_MAX_VALUE @property def color_temp_kelvin(self) -> int: diff --git a/tests/components/shelly/test_light.py b/tests/components/shelly/test_light.py index bd39e45746d5a6..959e6a471ba9c1 100644 --- a/tests/components/shelly/test_light.py +++ b/tests/components/shelly/test_light.py @@ -927,3 +927,29 @@ async def test_rpc_remove_cct_light( # there is no cct:0 in the status, so the CCT light entity should be removed assert get_entity(hass, LIGHT_DOMAIN, "cct:0") is None + + +async def test_rpc_cct_light_without_ct_range( + hass: HomeAssistant, + mock_rpc_device: Mock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test RPC CCT light without ct_range in the light config.""" + entity_id = f"{LIGHT_DOMAIN}.living_room_lamp" + + config = deepcopy(mock_rpc_device.config) + config["cct:0"] = {"id": 0, "name": "Living room lamp"} + monkeypatch.setattr(mock_rpc_device, "config", config) + + status = deepcopy(mock_rpc_device.status) + status["cct:0"] = {"id": 0, "output": False, "brightness": 77, "ct": 3666} + monkeypatch.setattr(mock_rpc_device, "status", status) + + await init_integration(hass, 3) + + assert (state := hass.states.get(entity_id)) + assert state.state == STATE_OFF + + # default values from constants are 2700 and 6500 + assert state.attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 2700 + assert state.attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 6500 From ec148e04596e9fe3f9fe7b7192ee41b9c5149e9f Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Sat, 20 Sep 2025 00:12:09 +1000 Subject: [PATCH 2/5] =?UTF-8?q?Add=20PM4=20(particulates=20<=204=CE=BCm)?= =?UTF-8?q?=20sensor=20and=20number=20device=20classes=20(#112867)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Erik Montnemery Co-authored-by: J. Nick Koston --- homeassistant/components/number/const.py | 7 +++++++ homeassistant/components/sensor/const.py | 8 ++++++++ homeassistant/components/sensor/device_condition.py | 3 +++ homeassistant/components/sensor/device_trigger.py | 3 +++ homeassistant/components/sensor/strings.json | 2 ++ tests/components/sensor/common.py | 1 + tests/components/sensor/test_device_condition.py | 2 +- tests/components/sensor/test_device_trigger.py | 2 +- tests/components/sensor/test_init.py | 2 ++ 9 files changed, 28 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index 402592888a2f6d..07a53c9cb61ee1 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -291,6 +291,12 @@ class NumberDeviceClass(StrEnum): Unit of measurement: `μg/m³` """ + PM4 = "pm4" + """Particulate matter <= 4 μm. + + Unit of measurement: `μg/m³` + """ + POWER_FACTOR = "power_factor" """Power factor. @@ -510,6 +516,7 @@ class NumberDeviceClass(StrEnum): NumberDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.PM25: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.PM4: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.POWER_FACTOR: {PERCENTAGE, None}, NumberDeviceClass.POWER: { UnitOfPower.MILLIWATT, diff --git a/homeassistant/components/sensor/const.py b/homeassistant/components/sensor/const.py index 098ac960fe89ef..b91bd26d410cfc 100644 --- a/homeassistant/components/sensor/const.py +++ b/homeassistant/components/sensor/const.py @@ -326,6 +326,12 @@ class SensorDeviceClass(StrEnum): Unit of measurement: `μg/m³` """ + PM4 = "pm4" + """Particulate matter <= 4 μm. + + Unit of measurement: `μg/m³` + """ + POWER_FACTOR = "power_factor" """Power factor. @@ -621,6 +627,7 @@ class SensorStateClass(StrEnum): SensorDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.PM25: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.PM4: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.POWER_FACTOR: {PERCENTAGE, None}, SensorDeviceClass.POWER: { UnitOfPower.MILLIWATT, @@ -755,6 +762,7 @@ class SensorStateClass(StrEnum): SensorDeviceClass.PM1: {SensorStateClass.MEASUREMENT}, SensorDeviceClass.PM10: {SensorStateClass.MEASUREMENT}, SensorDeviceClass.PM25: {SensorStateClass.MEASUREMENT}, + SensorDeviceClass.PM4: {SensorStateClass.MEASUREMENT}, SensorDeviceClass.POWER_FACTOR: {SensorStateClass.MEASUREMENT}, SensorDeviceClass.POWER: {SensorStateClass.MEASUREMENT}, SensorDeviceClass.PRECIPITATION: set(SensorStateClass), diff --git a/homeassistant/components/sensor/device_condition.py b/homeassistant/components/sensor/device_condition.py index 1ad5fe12e99daa..e238b1d9a9b0b3 100644 --- a/homeassistant/components/sensor/device_condition.py +++ b/homeassistant/components/sensor/device_condition.py @@ -65,6 +65,7 @@ CONF_IS_PM1 = "is_pm1" CONF_IS_PM10 = "is_pm10" CONF_IS_PM25 = "is_pm25" +CONF_IS_PM4 = "is_pm4" CONF_IS_POWER = "is_power" CONF_IS_POWER_FACTOR = "is_power_factor" CONF_IS_PRECIPITATION = "is_precipitation" @@ -126,6 +127,7 @@ SensorDeviceClass.PM1: [{CONF_TYPE: CONF_IS_PM1}], SensorDeviceClass.PM10: [{CONF_TYPE: CONF_IS_PM10}], SensorDeviceClass.PM25: [{CONF_TYPE: CONF_IS_PM25}], + SensorDeviceClass.PM4: [{CONF_TYPE: CONF_IS_PM4}], SensorDeviceClass.PRECIPITATION: [{CONF_TYPE: CONF_IS_PRECIPITATION}], SensorDeviceClass.PRECIPITATION_INTENSITY: [ {CONF_TYPE: CONF_IS_PRECIPITATION_INTENSITY} @@ -195,6 +197,7 @@ CONF_IS_PM1, CONF_IS_PM10, CONF_IS_PM25, + CONF_IS_PM4, CONF_IS_PRECIPITATION, CONF_IS_PRECIPITATION_INTENSITY, CONF_IS_PRESSURE, diff --git a/homeassistant/components/sensor/device_trigger.py b/homeassistant/components/sensor/device_trigger.py index ae2125962e8d43..1aacdbf507f935 100644 --- a/homeassistant/components/sensor/device_trigger.py +++ b/homeassistant/components/sensor/device_trigger.py @@ -64,6 +64,7 @@ CONF_PM1 = "pm1" CONF_PM10 = "pm10" CONF_PM25 = "pm25" +CONF_PM4 = "pm4" CONF_POWER = "power" CONF_POWER_FACTOR = "power_factor" CONF_PRECIPITATION = "precipitation" @@ -123,6 +124,7 @@ SensorDeviceClass.PM1: [{CONF_TYPE: CONF_PM1}], SensorDeviceClass.PM10: [{CONF_TYPE: CONF_PM10}], SensorDeviceClass.PM25: [{CONF_TYPE: CONF_PM25}], + SensorDeviceClass.PM4: [{CONF_TYPE: CONF_PM4}], SensorDeviceClass.POWER: [{CONF_TYPE: CONF_POWER}], SensorDeviceClass.POWER_FACTOR: [{CONF_TYPE: CONF_POWER_FACTOR}], SensorDeviceClass.PRECIPITATION: [{CONF_TYPE: CONF_PRECIPITATION}], @@ -193,6 +195,7 @@ CONF_PM1, CONF_PM10, CONF_PM25, + CONF_PM4, CONF_POWER, CONF_POWER_FACTOR, CONF_PRECIPITATION, diff --git a/homeassistant/components/sensor/strings.json b/homeassistant/components/sensor/strings.json index a8d06f8c0e927f..d721e20b244b04 100644 --- a/homeassistant/components/sensor/strings.json +++ b/homeassistant/components/sensor/strings.json @@ -34,6 +34,7 @@ "is_pm1": "Current {entity_name} PM1 concentration level", "is_pm10": "Current {entity_name} PM10 concentration level", "is_pm25": "Current {entity_name} PM2.5 concentration level", + "is_pm4": "Current {entity_name} PM4 concentration level", "is_power": "Current {entity_name} power", "is_power_factor": "Current {entity_name} power factor", "is_precipitation": "Current {entity_name} precipitation", @@ -90,6 +91,7 @@ "pm1": "{entity_name} PM1 concentration changes", "pm10": "{entity_name} PM10 concentration changes", "pm25": "{entity_name} PM2.5 concentration changes", + "pm4": "{entity_name} PM4 concentration changes", "power": "{entity_name} power changes", "power_factor": "{entity_name} power factor changes", "precipitation": "{entity_name} precipitation changes", diff --git a/tests/components/sensor/common.py b/tests/components/sensor/common.py index 1b9810a82509bd..ea5f6db0bf6167 100644 --- a/tests/components/sensor/common.py +++ b/tests/components/sensor/common.py @@ -80,6 +80,7 @@ SensorDeviceClass.PM10: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, SensorDeviceClass.PM1: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, SensorDeviceClass.PM25: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + SensorDeviceClass.PM4: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, SensorDeviceClass.POWER: UnitOfPower.KILO_WATT, SensorDeviceClass.POWER_FACTOR: PERCENTAGE, SensorDeviceClass.PRECIPITATION: UnitOfPrecipitationDepth.MILLIMETERS, diff --git a/tests/components/sensor/test_device_condition.py b/tests/components/sensor/test_device_condition.py index 88bec54c936779..a0e97ac9e0d22d 100644 --- a/tests/components/sensor/test_device_condition.py +++ b/tests/components/sensor/test_device_condition.py @@ -125,7 +125,7 @@ async def test_get_conditions( conditions = await async_get_device_automations( hass, DeviceAutomationType.CONDITION, device_entry.id ) - assert len(conditions) == 55 + assert len(conditions) == 56 assert conditions == unordered(expected_conditions) diff --git a/tests/components/sensor/test_device_trigger.py b/tests/components/sensor/test_device_trigger.py index 31bd0d2be550d3..1034f3473db583 100644 --- a/tests/components/sensor/test_device_trigger.py +++ b/tests/components/sensor/test_device_trigger.py @@ -126,7 +126,7 @@ async def test_get_triggers( triggers = await async_get_device_automations( hass, DeviceAutomationType.TRIGGER, device_entry.id ) - assert len(triggers) == 55 + assert len(triggers) == 56 assert triggers == unordered(expected_triggers) diff --git a/tests/components/sensor/test_init.py b/tests/components/sensor/test_init.py index 84dcf7742d8736..5d53cfe6d53a7a 100644 --- a/tests/components/sensor/test_init.py +++ b/tests/components/sensor/test_init.py @@ -2158,6 +2158,7 @@ async def test_non_numeric_device_class_with_unit_of_measurement( SensorDeviceClass.PM1, SensorDeviceClass.PM10, SensorDeviceClass.PM25, + SensorDeviceClass.PM4, SensorDeviceClass.POWER_FACTOR, SensorDeviceClass.POWER, SensorDeviceClass.PRECIPITATION_INTENSITY, @@ -3024,6 +3025,7 @@ def test_device_class_converters_are_complete() -> None: SensorDeviceClass.PM1, SensorDeviceClass.PM10, SensorDeviceClass.PM25, + SensorDeviceClass.PM4, SensorDeviceClass.SIGNAL_STRENGTH, SensorDeviceClass.SOUND_PRESSURE, SensorDeviceClass.SULPHUR_DIOXIDE, From 21c174e895c9cea12171dedf19a84e9183f5139e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 19 Sep 2025 09:20:00 -0500 Subject: [PATCH 3/5] Bump aioesphomeapi to 41.4.0 (#152618) Co-authored-by: Paulus Schoutsen --- homeassistant/components/esphome/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/esphome/snapshots/test_diagnostics.ambr | 1 + tests/components/esphome/test_diagnostics.py | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index 2cff387501959f..dd5bef1bc82371 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -17,7 +17,7 @@ "mqtt": ["esphome/discover/#"], "quality_scale": "platinum", "requirements": [ - "aioesphomeapi==41.3.0", + "aioesphomeapi==41.4.0", "esphome-dashboard-api==1.3.0", "bleak-esphome==3.3.0" ], diff --git a/requirements_all.txt b/requirements_all.txt index 37a65427264d53..e99653e2f110f4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -247,7 +247,7 @@ aioelectricitymaps==1.1.1 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==41.3.0 +aioesphomeapi==41.4.0 # homeassistant.components.flo aioflo==2021.11.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b0c72d032bc36a..3b3ef69205b171 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -235,7 +235,7 @@ aioelectricitymaps==1.1.1 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==41.3.0 +aioesphomeapi==41.4.0 # homeassistant.components.flo aioflo==2021.11.0 diff --git a/tests/components/esphome/snapshots/test_diagnostics.ambr b/tests/components/esphome/snapshots/test_diagnostics.ambr index 8ff30160a0192e..731acd0eb35398 100644 --- a/tests/components/esphome/snapshots/test_diagnostics.ambr +++ b/tests/components/esphome/snapshots/test_diagnostics.ambr @@ -109,6 +109,7 @@ 'uses_password': False, 'voice_assistant_feature_flags': 0, 'webserver_port': 0, + 'zwave_home_id': 0, 'zwave_proxy_feature_flags': 0, }), 'services': list([ diff --git a/tests/components/esphome/test_diagnostics.py b/tests/components/esphome/test_diagnostics.py index ca0b7ff4c555b5..76b2dc87ed3db3 100644 --- a/tests/components/esphome/test_diagnostics.py +++ b/tests/components/esphome/test_diagnostics.py @@ -146,6 +146,7 @@ async def test_diagnostics_with_bluetooth( "legacy_voice_assistant_version": 0, "voice_assistant_feature_flags": 0, "webserver_port": 0, + "zwave_home_id": 0, "zwave_proxy_feature_flags": 0, }, "services": [], From 21bfe610d15014cf869b610e5e4f4c636f89c2d5 Mon Sep 17 00:00:00 2001 From: Aidan Timson Date: Fri, 19 Sep 2025 16:07:15 +0100 Subject: [PATCH 4/5] Update systembridgeconnector to 5.1.0 (#152623) --- homeassistant/components/system_bridge/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/system_bridge/manifest.json b/homeassistant/components/system_bridge/manifest.json index c19f36f14dd920..d2d9bb6e65725f 100644 --- a/homeassistant/components/system_bridge/manifest.json +++ b/homeassistant/components/system_bridge/manifest.json @@ -9,6 +9,6 @@ "integration_type": "device", "iot_class": "local_push", "loggers": ["systembridgeconnector"], - "requirements": ["systembridgeconnector==4.1.10"], + "requirements": ["systembridgeconnector==5.1.0"], "zeroconf": ["_system-bridge._tcp.local."] } diff --git a/requirements_all.txt b/requirements_all.txt index e99653e2f110f4..8d3577a3ccb907 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2898,7 +2898,7 @@ switchbot-api==2.8.0 synology-srm==0.2.0 # homeassistant.components.system_bridge -systembridgeconnector==4.1.10 +systembridgeconnector==5.1.0 # homeassistant.components.tailscale tailscale==0.6.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3b3ef69205b171..d3d98bba7e7d1f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2402,7 +2402,7 @@ surepy==0.9.0 switchbot-api==2.8.0 # homeassistant.components.system_bridge -systembridgeconnector==4.1.10 +systembridgeconnector==5.1.0 # homeassistant.components.tailscale tailscale==0.6.2 From f63eee38892a8606482224348af780f187902177 Mon Sep 17 00:00:00 2001 From: Norbert Rittel Date: Fri, 19 Sep 2025 17:07:46 +0200 Subject: [PATCH 5/5] Fix typo and sentence-casing in `honeywell` exception string (#152619) --- homeassistant/components/honeywell/strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/honeywell/strings.json b/homeassistant/components/honeywell/strings.json index 67295ec58027de..d19e33d709ea0c 100644 --- a/homeassistant/components/honeywell/strings.json +++ b/homeassistant/components/honeywell/strings.json @@ -88,7 +88,7 @@ "message": "Honeywell set temperature failed: invalid temperature {temperature}" }, "temp_failed_range": { - "message": "Honeywell set temperature failed: temperature out of range. Mode: {mode}, Heat Temperuature: {heat}, Cool Temperature: {cool}" + "message": "Honeywell set temperature failed: temperature out of range. Mode: {mode}, Heat temperature: {heat}, Cool temperature: {cool}" }, "set_hold_failed": { "message": "Honeywell could not set permanent hold"