diff --git a/homeassistant/components/caldav/manifest.json b/homeassistant/components/caldav/manifest.json index 619523ae7a1..e0d598e6493 100644 --- a/homeassistant/components/caldav/manifest.json +++ b/homeassistant/components/caldav/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/caldav", "iot_class": "cloud_polling", "loggers": ["caldav", "vobject"], - "requirements": ["caldav==1.3.8"] + "requirements": ["caldav==1.3.9"] } diff --git a/homeassistant/components/enigma2/manifest.json b/homeassistant/components/enigma2/manifest.json index e298b3b714f..0de4adc13b8 100644 --- a/homeassistant/components/enigma2/manifest.json +++ b/homeassistant/components/enigma2/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/enigma2", "iot_class": "local_polling", "loggers": ["openwebif"], - "requirements": ["openwebifpy==4.2.1"] + "requirements": ["openwebifpy==4.2.4"] } diff --git a/homeassistant/components/enigma2/media_player.py b/homeassistant/components/enigma2/media_player.py index c3be9c6f7a3..b73f8b51c4d 100644 --- a/homeassistant/components/enigma2/media_player.py +++ b/homeassistant/components/enigma2/media_player.py @@ -107,7 +107,7 @@ async def async_setup_platform( device = OpenWebIfDevice( host=session, - turn_off_to_deep=config.get(CONF_DEEP_STANDBY), + turn_off_to_deep=config.get(CONF_DEEP_STANDBY, False), source_bouquet=config.get(CONF_SOURCE_BOUQUET), ) diff --git a/homeassistant/components/group/sensor.py b/homeassistant/components/group/sensor.py index 8e1a0a24207..7334831211d 100644 --- a/homeassistant/components/group/sensor.py +++ b/homeassistant/components/group/sensor.py @@ -396,7 +396,7 @@ class SensorGroup(GroupEntity, SensorEntity): self._state_incorrect.add(entity_id) _LOGGER.warning( "Unable to use state. Only entities with correct unit of measurement" - " is supported when having a device class," + " is supported," " entity %s, value %s with device class %s" " and unit of measurement %s excluded from calculation in %s", entity_id, @@ -548,19 +548,28 @@ class SensorGroup(GroupEntity, SensorEntity): # Ensure only valid unit of measurements for the specific device class can be used if ( - # Test if uom's in device class is convertible - (device_class := self.device_class) in UNIT_CONVERTERS - and all( - uom in UNIT_CONVERTERS[device_class].VALID_UNITS - for uom in unit_of_measurements + ( + # Test if uom's in device class is convertible + (device_class := self.device_class) in UNIT_CONVERTERS + and all( + uom in UNIT_CONVERTERS[device_class].VALID_UNITS + for uom in unit_of_measurements + ) ) - ) or ( - # Test if uom's in device class is not convertible - device_class - and device_class not in UNIT_CONVERTERS - and device_class in DEVICE_CLASS_UNITS - and all( - uom in DEVICE_CLASS_UNITS[device_class] for uom in unit_of_measurements + or ( + # Test if uom's in device class is not convertible + device_class + and device_class not in UNIT_CONVERTERS + and device_class in DEVICE_CLASS_UNITS + and all( + uom in DEVICE_CLASS_UNITS[device_class] + for uom in unit_of_measurements + ) + ) + or ( + # Test no device class and all uom's are same + device_class is None + and all(x == unit_of_measurements[0] for x in unit_of_measurements) ) ): async_delete_issue( @@ -608,6 +617,7 @@ class SensorGroup(GroupEntity, SensorEntity): """Return valid units. If device class is set and compatible unit of measurements. + If device class is not set, use one unit of measurement. """ if ( device_class := self.device_class @@ -621,4 +631,6 @@ class SensorGroup(GroupEntity, SensorEntity): ): valid_uoms: set = DEVICE_CLASS_UNITS[device_class] return valid_uoms + if device_class is None and self.native_unit_of_measurement: + return {self.native_unit_of_measurement} return set() diff --git a/homeassistant/components/group/strings.json b/homeassistant/components/group/strings.json index ba571bb1008..f9039fb896e 100644 --- a/homeassistant/components/group/strings.json +++ b/homeassistant/components/group/strings.json @@ -257,7 +257,7 @@ }, "uoms_not_matching_no_device_class": { "title": "Unit of measurements is not correct", - "description": "Unit of measurements `{uoms}` of input sensors `{source_entities}` are not compatible using no device class of sensor group `{entity_id}`.\n\nPlease correct the unit of measurements on the source entities or set a proper device class on the sensor group and reload the group sensor to fix this issue." + "description": "Unit of measurements `{uoms}` of input sensors `{source_entities}` are not compatible when not using a device class on sensor group `{entity_id}`.\n\nPlease correct the unit of measurements on the source entities or set a proper device class on the sensor group and reload the group sensor to fix this issue." }, "device_classes_not_matching": { "title": "Device classes is not correct", diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 0286fdef238..37aa26f6313 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -43,6 +43,7 @@ class LutronSwitch(LutronDevice, SwitchEntity): """Representation of a Lutron Switch.""" _lutron_device: Output + _attr_name = None def turn_on(self, **kwargs: Any) -> None: """Turn the switch on.""" diff --git a/homeassistant/components/opower/manifest.json b/homeassistant/components/opower/manifest.json index e654c044c16..418f2a5723b 100644 --- a/homeassistant/components/opower/manifest.json +++ b/homeassistant/components/opower/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/opower", "iot_class": "cloud_polling", "loggers": ["opower"], - "requirements": ["opower==0.2.0"] + "requirements": ["opower==0.3.1"] } diff --git a/homeassistant/components/profiler/manifest.json b/homeassistant/components/profiler/manifest.json index d96f76d25a4..ceaab458e69 100644 --- a/homeassistant/components/profiler/manifest.json +++ b/homeassistant/components/profiler/manifest.json @@ -5,5 +5,9 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/profiler", "quality_scale": "internal", - "requirements": ["pyprof2calltree==1.4.5", "guppy3==3.1.4", "objgraph==3.5.0"] + "requirements": [ + "pyprof2calltree==1.4.5", + "guppy3==3.1.4.post1", + "objgraph==3.5.0" + ] } diff --git a/homeassistant/components/roomba/manifest.json b/homeassistant/components/roomba/manifest.json index 3d524dcf1d8..e2876e9f3b4 100644 --- a/homeassistant/components/roomba/manifest.json +++ b/homeassistant/components/roomba/manifest.json @@ -24,7 +24,7 @@ "documentation": "https://www.home-assistant.io/integrations/roomba", "iot_class": "local_push", "loggers": ["paho_mqtt", "roombapy"], - "requirements": ["roombapy==1.6.12"], + "requirements": ["roombapy==1.6.13"], "zeroconf": [ { "type": "_amzn-alexa._tcp.local.", diff --git a/homeassistant/components/wyoming/config_flow.py b/homeassistant/components/wyoming/config_flow.py index b766fc80c89..528165712b5 100644 --- a/homeassistant/components/wyoming/config_flow.py +++ b/homeassistant/components/wyoming/config_flow.py @@ -15,7 +15,7 @@ from homeassistant.data_entry_flow import FlowResult from .const import DOMAIN from .data import WyomingService -_LOGGER = logging.getLogger() +_LOGGER = logging.getLogger(__name__) STEP_USER_DATA_SCHEMA = vol.Schema( { @@ -64,6 +64,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self, discovery_info: hassio.HassioServiceInfo ) -> FlowResult: """Handle Supervisor add-on discovery.""" + _LOGGER.debug("Supervisor discovery info: %s", discovery_info) await self.async_set_unique_id(discovery_info.uuid) self._abort_if_unique_id_configured() @@ -105,7 +106,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self, discovery_info: zeroconf.ZeroconfServiceInfo ) -> FlowResult: """Handle zeroconf discovery.""" - _LOGGER.debug("Discovery info: %s", discovery_info) + _LOGGER.debug("Zeroconf discovery info: %s", discovery_info) if discovery_info.port is None: return self.async_abort(reason="no_port") diff --git a/homeassistant/const.py b/homeassistant/const.py index da3323e7562..4c1f1ab0448 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -16,7 +16,7 @@ from .helpers.deprecation import ( APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 2 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 11, 0) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index b9c5df68456..afbc1c63a35 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -36,7 +36,7 @@ janus==1.0.0 Jinja2==3.1.3 lru-dict==1.3.0 mutagen==1.47.0 -orjson==3.9.14 +orjson==3.9.15 packaging>=23.1 paho-mqtt==1.6.1 Pillow==10.2.0 diff --git a/pyproject.toml b/pyproject.toml index fb6831f0132..8f7c167edbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.2.3" +version = "2024.2.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" @@ -46,7 +46,7 @@ dependencies = [ "cryptography==42.0.2", # pyOpenSSL 23.2.0 is required to work with cryptography 41+ "pyOpenSSL==24.0.0", - "orjson==3.9.14", + "orjson==3.9.15", "packaging>=23.1", "pip>=21.3.1", "python-slugify==8.0.1", diff --git a/requirements.txt b/requirements.txt index 76ca93d998d..215df08339d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ lru-dict==1.3.0 PyJWT==2.8.0 cryptography==42.0.2 pyOpenSSL==24.0.0 -orjson==3.9.14 +orjson==3.9.15 packaging>=23.1 pip>=21.3.1 python-slugify==8.0.1 diff --git a/requirements_all.txt b/requirements_all.txt index 6666763de46..a77b6b42a2d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -624,7 +624,7 @@ buienradar==1.0.5 cached_ipaddress==0.3.0 # homeassistant.components.caldav -caldav==1.3.8 +caldav==1.3.9 # homeassistant.components.circuit circuit-webhook==1.0.1 @@ -997,7 +997,7 @@ gspread==5.5.0 gstreamer-player==1.1.2 # homeassistant.components.profiler -guppy3==3.1.4 +guppy3==3.1.4.post1 # homeassistant.components.iaqualink h2==4.1.0 @@ -1459,7 +1459,7 @@ openhomedevice==2.2.0 opensensemap-api==0.2.0 # homeassistant.components.enigma2 -openwebifpy==4.2.1 +openwebifpy==4.2.4 # homeassistant.components.luci openwrt-luci-rpc==1.1.16 @@ -1468,7 +1468,7 @@ openwrt-luci-rpc==1.1.16 openwrt-ubus-rpc==0.0.2 # homeassistant.components.opower -opower==0.2.0 +opower==0.3.1 # homeassistant.components.oralb oralb-ble==0.17.6 @@ -2450,7 +2450,7 @@ rokuecp==0.19.1 romy==0.0.7 # homeassistant.components.roomba -roombapy==1.6.12 +roombapy==1.6.13 # homeassistant.components.roon roonapi==0.1.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3c3bfc92575..16ea6cca5a0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -523,7 +523,7 @@ buienradar==1.0.5 cached_ipaddress==0.3.0 # homeassistant.components.caldav -caldav==1.3.8 +caldav==1.3.9 # homeassistant.components.coinbase coinbase==2.1.0 @@ -805,7 +805,7 @@ growattServer==1.3.0 gspread==5.5.0 # homeassistant.components.profiler -guppy3==3.1.4 +guppy3==3.1.4.post1 # homeassistant.components.iaqualink h2==4.1.0 @@ -1156,7 +1156,7 @@ openerz-api==0.3.0 openhomedevice==2.2.0 # homeassistant.components.opower -opower==0.2.0 +opower==0.3.1 # homeassistant.components.oralb oralb-ble==0.17.6 @@ -1872,7 +1872,7 @@ rokuecp==0.19.1 romy==0.0.7 # homeassistant.components.roomba -roombapy==1.6.12 +roombapy==1.6.13 # homeassistant.components.roon roonapi==0.1.6 diff --git a/tests/components/group/test_sensor.py b/tests/components/group/test_sensor.py index ec6905a500f..fb3c1b6d215 100644 --- a/tests/components/group/test_sensor.py +++ b/tests/components/group/test_sensor.py @@ -424,6 +424,101 @@ async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: assert state.state == str(float(sum(VALUES))) +async def test_sensor_with_uoms_but_no_device_class( + hass: HomeAssistant, + issue_registry: ir.IssueRegistry, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the sensor works with same uom when there is no device class.""" + config = { + SENSOR_DOMAIN: { + "platform": GROUP_DOMAIN, + "name": "test_sum", + "type": "sum", + "entities": ["sensor.test_1", "sensor.test_2", "sensor.test_3"], + "unique_id": "very_unique_id_last_sensor", + } + } + + entity_ids = config["sensor"]["entities"] + + hass.states.async_set( + entity_ids[0], + VALUES[0], + { + "device_class": SensorDeviceClass.POWER, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": "W", + }, + ) + hass.states.async_set( + entity_ids[1], + VALUES[1], + { + "device_class": SensorDeviceClass.POWER, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": "W", + }, + ) + hass.states.async_set( + entity_ids[2], + VALUES[2], + { + "unit_of_measurement": "W", + }, + ) + + await hass.async_block_till_done() + + assert await async_setup_component(hass, "sensor", config) + await hass.async_block_till_done() + + state = hass.states.get("sensor.test_sum") + assert state.attributes.get("device_class") is None + assert state.attributes.get("state_class") is None + assert state.attributes.get("unit_of_measurement") == "W" + assert state.state == str(float(sum(VALUES))) + + assert not issue_registry.issues + + hass.states.async_set( + entity_ids[0], + VALUES[0], + { + "device_class": SensorDeviceClass.POWER, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": "kW", + }, + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.test_sum") + assert state.attributes.get("device_class") is None + assert state.attributes.get("state_class") is None + assert state.attributes.get("unit_of_measurement") == "W" + assert state.state == STATE_UNKNOWN + + assert ( + "Unable to use state. Only entities with correct unit of measurement is supported" + in caplog.text + ) + + hass.states.async_set( + entity_ids[0], + VALUES[0], + { + "device_class": SensorDeviceClass.POWER, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": "W", + }, + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.test_sum") + assert state.attributes.get("device_class") is None + assert state.attributes.get("state_class") is None + assert state.attributes.get("unit_of_measurement") == "W" + assert state.state == str(float(sum(VALUES))) + + async def test_sensor_calculated_properties_not_same( hass: HomeAssistant, issue_registry: ir.IssueRegistry ) -> None: @@ -616,7 +711,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( assert ( "Unable to use state. Only entities with correct unit of measurement is" - " supported when having a device class" + " supported" ) not in caplog.text hass.states.async_set( @@ -637,7 +732,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( assert ( "Unable to use state. Only entities with correct unit of measurement is" - " supported when having a device class, entity sensor.test_3, value 15.3 with" + " supported, entity sensor.test_3, value 15.3 with" " device class humidity and unit of measurement None excluded from calculation" " in sensor.test_sum" ) in caplog.text