From 599c20c76ecdb53ecc87193145fa9de11bb1f4b0 Mon Sep 17 00:00:00 2001 From: bsmappee <58250533+bsmappee@users.noreply.github.com> Date: Tue, 7 Dec 2021 19:15:51 +0100 Subject: [PATCH 01/25] Bump pysmappee to 0.2.29 (#61160) --- homeassistant/components/smappee/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/smappee/manifest.json b/homeassistant/components/smappee/manifest.json index 91192a13484..6a1edaf41ae 100644 --- a/homeassistant/components/smappee/manifest.json +++ b/homeassistant/components/smappee/manifest.json @@ -5,7 +5,7 @@ "documentation": "https://www.home-assistant.io/integrations/smappee", "dependencies": ["http"], "requirements": [ - "pysmappee==0.2.27" + "pysmappee==0.2.29" ], "codeowners": [ "@bsmappee" diff --git a/requirements_all.txt b/requirements_all.txt index 8e079958d13..24b1073952d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1802,7 +1802,7 @@ pyskyqhub==0.1.3 pysma==0.6.9 # homeassistant.components.smappee -pysmappee==0.2.27 +pysmappee==0.2.29 # homeassistant.components.smartthings pysmartapp==0.3.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e1f9e1f7351..1c8e3e05459 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1109,7 +1109,7 @@ pysignalclirestapi==0.3.4 pysma==0.6.9 # homeassistant.components.smappee -pysmappee==0.2.27 +pysmappee==0.2.29 # homeassistant.components.smartthings pysmartapp==0.3.3 From ff2e2656b3e1d72ffbbcba73a447dc7062023d4a Mon Sep 17 00:00:00 2001 From: majuss Date: Mon, 13 Dec 2021 09:07:52 +0100 Subject: [PATCH 02/25] Upgrade lupupy to 0.0.24 (#61598) --- homeassistant/components/lupusec/manifest.json | 3 +-- requirements_all.txt | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/lupusec/manifest.json b/homeassistant/components/lupusec/manifest.json index ce200fe196a..126fa407a37 100644 --- a/homeassistant/components/lupusec/manifest.json +++ b/homeassistant/components/lupusec/manifest.json @@ -1,9 +1,8 @@ { - "disabled": "Library has incompatible requirements.", "domain": "lupusec", "name": "Lupus Electronics LUPUSEC", "documentation": "https://www.home-assistant.io/integrations/lupusec", - "requirements": ["lupupy==0.0.21"], + "requirements": ["lupupy==0.0.24"], "codeowners": ["@majuss"], "iot_class": "local_polling" } diff --git a/requirements_all.txt b/requirements_all.txt index 24b1073952d..ce0b2b9ea3b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -968,6 +968,9 @@ london-tube-status==0.2 # homeassistant.components.luftdaten luftdaten==0.7.1 +# homeassistant.components.lupusec +lupupy==0.0.24 + # homeassistant.components.lw12wifi lw12==0.9.2 From 1833ab96dc5d291e669f4a67c316e9e3ef7ae188 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Mon, 13 Dec 2021 08:41:45 -0800 Subject: [PATCH 03/25] Suppress errors for legacy nest api when using media source (#61629) --- homeassistant/components/nest/media_source.py | 3 ++ tests/components/nest/test_media_source.py | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/homeassistant/components/nest/media_source.py b/homeassistant/components/nest/media_source.py index 7c33e004b2b..8b62f2f4087 100644 --- a/homeassistant/components/nest/media_source.py +++ b/homeassistant/components/nest/media_source.py @@ -63,6 +63,9 @@ async def async_get_media_source(hass: HomeAssistant) -> MediaSource: async def get_media_source_devices(hass: HomeAssistant) -> Mapping[str, Device]: """Return a mapping of device id to eligible Nest event media devices.""" + if DATA_SUBSCRIBER not in hass.data[DOMAIN]: + # Integration unloaded, or is legacy nest integration + return {} subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager = await subscriber.async_get_device_manager() device_registry = await hass.helpers.device_registry.async_get_registry() diff --git a/tests/components/nest/test_media_source.py b/tests/components/nest/test_media_source.py index f52b89c4f4d..95f2afa8a06 100644 --- a/tests/components/nest/test_media_source.py +++ b/tests/components/nest/test_media_source.py @@ -16,6 +16,7 @@ from homeassistant.components import media_source from homeassistant.components.media_player.errors import BrowseError from homeassistant.components.media_source import const from homeassistant.components.media_source.error import Unresolvable +from homeassistant.config_entries import ConfigEntryState from homeassistant.helpers import device_registry as dr from homeassistant.helpers.template import DATE_STR_FORMAT import homeassistant.util.dt as dt_util @@ -164,6 +165,37 @@ async def test_supported_device(hass, auth): assert len(browse.children) == 0 +async def test_integration_unloaded(hass, auth): + """Test the media player loads, but has no devices, when config unloaded.""" + await async_setup_devices( + hass, + auth, + CAMERA_DEVICE_TYPE, + CAMERA_TRAITS, + ) + + browse = await media_source.async_browse_media(hass, f"{const.URI_SCHEME}{DOMAIN}") + assert browse.domain == DOMAIN + assert browse.identifier == "" + assert browse.title == "Nest" + assert len(browse.children) == 1 + + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + entry = entries[0] + assert entry.state is ConfigEntryState.LOADED + + assert await hass.config_entries.async_unload(entry.entry_id) + assert entry.state == ConfigEntryState.NOT_LOADED + + # No devices returned + browse = await media_source.async_browse_media(hass, f"{const.URI_SCHEME}{DOMAIN}") + assert browse.domain == DOMAIN + assert browse.identifier == "" + assert browse.title == "Nest" + assert len(browse.children) == 0 + + async def test_camera_event(hass, auth, hass_client): """Test a media source and image created for an event.""" event_timestamp = dt_util.now() From ed041d5b7c26b61965834897410e97d9657770b0 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Dec 2021 08:39:11 -0800 Subject: [PATCH 04/25] Bump total_connect_client to 2021.12 (#61634) --- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 0eec41968cc..15854881ae3 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,7 @@ "domain": "totalconnect", "name": "Total Connect", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==2021.11.4"], + "requirements": ["total_connect_client==2021.12"], "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true, diff --git a/requirements_all.txt b/requirements_all.txt index ce0b2b9ea3b..ca314d0c7ae 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2329,7 +2329,7 @@ tololib==0.1.0b3 toonapi==0.2.1 # homeassistant.components.totalconnect -total_connect_client==2021.11.4 +total_connect_client==2021.12 # homeassistant.components.tplink_lte tp-connected==0.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1c8e3e05459..24233f27008 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1370,7 +1370,7 @@ tololib==0.1.0b3 toonapi==0.2.1 # homeassistant.components.totalconnect -total_connect_client==2021.11.4 +total_connect_client==2021.12 # homeassistant.components.transmission transmissionrpc==0.11 From 791c2f4b8a36a5725aeef625bdd482631fa88233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 13 Dec 2021 17:14:37 +0100 Subject: [PATCH 05/25] Add additional-tag to machine builds (#61693) --- .github/workflows/builder.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index 3f8dea3b657..e7dc7ebb270 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -131,7 +131,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build base image - uses: home-assistant/builder@2021.11.4 + uses: home-assistant/builder@2021.12.0 with: args: | $BUILD_ARGS \ @@ -170,6 +170,17 @@ jobs: - name: Checkout the repository uses: actions/checkout@v2.4.0 + - name: Set build additional args + run: | + # Create general tags + if [[ "${{ needs.init.outputs.version }}" =~ d ]]; then + echo "BUILD_ARGS=--additional-tag dev" >> $GITHUB_ENV + elif [[ "${{ needs.init.outputs.version }}" =~ b ]]; then + echo "BUILD_ARGS=--additional-tag beta" >> $GITHUB_ENV + else + echo "BUILD_ARGS=--additional-tag stable" >> $GITHUB_ENV + fi + - name: Login to DockerHub uses: docker/login-action@v1.10.0 with: @@ -184,7 +195,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build base image - uses: home-assistant/builder@2021.11.4 + uses: home-assistant/builder@2021.12.0 with: args: | $BUILD_ARGS \ From 52c96654a457938f9681586c462f82d02d0144a2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Dec 2021 10:46:57 -0800 Subject: [PATCH 06/25] Bump aiohue to 3.0.4 (#61709) --- homeassistant/components/hue/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json index ee337cd3d71..7f424f14594 100644 --- a/homeassistant/components/hue/manifest.json +++ b/homeassistant/components/hue/manifest.json @@ -3,7 +3,7 @@ "name": "Philips Hue", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/hue", - "requirements": ["aiohue==3.0.3"], + "requirements": ["aiohue==3.0.4"], "ssdp": [ { "manufacturer": "Royal Philips Electronics", diff --git a/requirements_all.txt b/requirements_all.txt index ca314d0c7ae..76c24fcd989 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -186,7 +186,7 @@ aiohomekit==0.6.4 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==3.0.3 +aiohue==3.0.4 # homeassistant.components.imap aioimaplib==0.9.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 24233f27008..1e7860c893a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -131,7 +131,7 @@ aiohomekit==0.6.4 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==3.0.3 +aiohue==3.0.4 # homeassistant.components.apache_kafka aiokafka==0.6.0 From 37ecbc53a7a675ae60b35013f313695d5511e6f1 Mon Sep 17 00:00:00 2001 From: Vilppu Vuorinen Date: Mon, 13 Dec 2021 23:52:35 +0200 Subject: [PATCH 07/25] Update pymelcloud to 2.5.6 (#61717) --- homeassistant/components/melcloud/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/melcloud/manifest.json b/homeassistant/components/melcloud/manifest.json index f875984453d..355f4c9058b 100644 --- a/homeassistant/components/melcloud/manifest.json +++ b/homeassistant/components/melcloud/manifest.json @@ -3,7 +3,7 @@ "name": "MELCloud", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/melcloud", - "requirements": ["pymelcloud==2.5.5"], + "requirements": ["pymelcloud==2.5.6"], "codeowners": ["@vilppuvuorinen"], "iot_class": "cloud_polling" } diff --git a/requirements_all.txt b/requirements_all.txt index 76c24fcd989..775246eb32d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1631,7 +1631,7 @@ pymazda==0.2.2 pymediaroom==0.6.4.1 # homeassistant.components.melcloud -pymelcloud==2.5.5 +pymelcloud==2.5.6 # homeassistant.components.meteoclimatic pymeteoclimatic==0.0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1e7860c893a..fa589181636 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -995,7 +995,7 @@ pymata-express==1.19 pymazda==0.2.2 # homeassistant.components.melcloud -pymelcloud==2.5.5 +pymelcloud==2.5.6 # homeassistant.components.meteoclimatic pymeteoclimatic==0.0.6 From 0626bc8b4fc9943bb7ae9791f2b94a40c2f752fa Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 14 Dec 2021 01:04:55 +0100 Subject: [PATCH 08/25] Add check for incompatible device trigger in Hue integration (#61726) --- .../components/hue/v2/device_trigger.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/hue/v2/device_trigger.py b/homeassistant/components/hue/v2/device_trigger.py index 74863a1897e..3f474cdf70b 100644 --- a/homeassistant/components/hue/v2/device_trigger.py +++ b/homeassistant/components/hue/v2/device_trigger.py @@ -7,6 +7,7 @@ from aiohue.v2.models.button import ButtonEvent from aiohue.v2.models.resource import ResourceTypes import voluptuous as vol +from homeassistant.components import persistent_notification from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA from homeassistant.components.homeassistant.triggers import event as event_trigger from homeassistant.const import ( @@ -35,7 +36,7 @@ if TYPE_CHECKING: TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend( { vol.Required(CONF_TYPE): str, - vol.Required(CONF_SUBTYPE): int, + vol.Required(CONF_SUBTYPE): vol.Union(int, str), vol.Optional(CONF_UNIQUE_ID): str, } ) @@ -54,6 +55,33 @@ DEVICE_SPECIFIC_EVENT_TYPES = { } +def check_invalid_device_trigger( + bridge: HueBridge, + config: ConfigType, + device_entry: DeviceEntry, + automation_info: AutomationTriggerInfo | None = None, +): + """Check automation config for deprecated format.""" + # NOTE: Remove this check after 2022.6 + if isinstance(config["subtype"], int): + return + # found deprecated V1 style trigger, notify the user that it should be adjusted + msg = ( + f"Incompatible device trigger detected for " + f"[{device_entry.name}](/config/devices/device/{device_entry.id}) " + "Please manually fix the outdated automation(s) once to fix this issue." + ) + if automation_info: + automation_id = automation_info["variables"]["this"]["attributes"]["id"] # type: ignore + msg += f"\n\n[Check it out](/config/automation/edit/{automation_id})." + persistent_notification.async_create( + bridge.hass, + msg, + title="Outdated device trigger found", + notification_id=f"hue_trigger_{device_entry.id}", + ) + + async def async_validate_trigger_config( bridge: "HueBridge", device_entry: DeviceEntry, @@ -61,6 +89,7 @@ async def async_validate_trigger_config( ): """Validate config.""" config = TRIGGER_SCHEMA(config) + check_invalid_device_trigger(bridge, config, device_entry) return config @@ -84,6 +113,7 @@ async def async_attach_trigger( }, } ) + check_invalid_device_trigger(bridge, config, device_entry, automation_info) return await event_trigger.async_attach_trigger( hass, event_config, action, automation_info, platform_type="device" ) From 03b88af032d2b0e667b43ede3d2ad89f37637a73 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 14 Dec 2021 20:24:37 +0100 Subject: [PATCH 09/25] Fix turn_off with transition for grouped Hue lights (#61728) * fix turn_off with transition for grouped hue lights * add test --- homeassistant/components/hue/v2/group.py | 31 +++++++++++++++++++----- tests/components/hue/test_light_v2.py | 31 +++++++++++++++++++++++- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/hue/v2/group.py b/homeassistant/components/hue/v2/group.py index 08f1dc72325..e29e015f85d 100644 --- a/homeassistant/components/hue/v2/group.py +++ b/homeassistant/components/hue/v2/group.py @@ -185,12 +185,31 @@ class GroupedHueLight(HueBaseEntity, LightEntity): async def async_turn_off(self, **kwargs: Any) -> None: """Turn the light off.""" - await self.bridge.async_request_call( - self.controller.set_state, - id=self.resource.id, - on=False, - allowed_errors=ALLOWED_ERRORS, - ) + transition = kwargs.get(ATTR_TRANSITION) + if transition is not None: + # hue transition duration is in milliseconds + transition = int(transition * 1000) + + # NOTE: a grouped_light can only handle turn on/off + # To set other features, you'll have to control the attached lights + if transition is None: + await self.bridge.async_request_call( + self.controller.set_state, + id=self.resource.id, + on=False, + allowed_errors=ALLOWED_ERRORS, + ) + return + + # redirect all other feature commands to underlying lights + for light in self.controller.get_lights(self.resource.id): + await self.bridge.async_request_call( + self.api.lights.set_state, + light.id, + on=False, + transition_time=transition, + allowed_errors=ALLOWED_ERRORS, + ) @callback def on_update(self) -> None: diff --git a/tests/components/hue/test_light_v2.py b/tests/components/hue/test_light_v2.py index 362b7076a92..f2200b0c745 100644 --- a/tests/components/hue/test_light_v2.py +++ b/tests/components/hue/test_light_v2.py @@ -295,7 +295,12 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data): await hass.services.async_call( "light", "turn_on", - {"entity_id": test_light_id, "brightness_pct": 100, "xy_color": (0.123, 0.123)}, + { + "entity_id": test_light_id, + "brightness_pct": 100, + "xy_color": (0.123, 0.123), + "transition": 6, + }, blocking=True, ) @@ -308,6 +313,9 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data): ) assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["x"] == 0.123 assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["y"] == 0.123 + assert ( + mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000 + ) # Now generate update events by emitting the json we've sent as incoming events for index in range(0, 3): @@ -346,3 +354,24 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data): test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "off" + + # Test calling the turn off service on a grouped light with transition + mock_bridge_v2.mock_requests.clear() + test_light_id = "light.test_zone" + await hass.services.async_call( + "light", + "turn_off", + { + "entity_id": test_light_id, + "transition": 6, + }, + blocking=True, + ) + + # PUT request should have been sent to ALL group lights with correct params + assert len(mock_bridge_v2.mock_requests) == 3 + for index in range(0, 3): + assert mock_bridge_v2.mock_requests[index]["json"]["on"]["on"] is False + assert ( + mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000 + ) From bbef38964de83b1af8a062cc29a0b5390f1acdc8 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 14 Dec 2021 01:27:58 +0100 Subject: [PATCH 10/25] Fix Flash effect for Hue lights (#61733) --- homeassistant/components/hue/v2/group.py | 8 ++++++++ homeassistant/components/hue/v2/light.py | 9 +++++++++ tests/components/hue/test_light_v2.py | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/homeassistant/components/hue/v2/group.py b/homeassistant/components/hue/v2/group.py index e29e015f85d..c5f7ae5d926 100644 --- a/homeassistant/components/hue/v2/group.py +++ b/homeassistant/components/hue/v2/group.py @@ -6,16 +6,19 @@ from typing import Any from aiohue.v2 import HueBridgeV2 from aiohue.v2.controllers.events import EventType from aiohue.v2.controllers.groups import GroupedLight, Room, Zone +from aiohue.v2.models.feature import AlertEffectType from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, + ATTR_FLASH, ATTR_TRANSITION, ATTR_XY_COLOR, COLOR_MODE_BRIGHTNESS, COLOR_MODE_COLOR_TEMP, COLOR_MODE_ONOFF, COLOR_MODE_XY, + SUPPORT_FLASH, SUPPORT_TRANSITION, LightEntity, ) @@ -32,6 +35,7 @@ ALLOWED_ERRORS = [ 'device (groupedLight) is "soft off", command (on) may not have effect', "device (light) has communication issues, command (on) may not have effect", 'device (light) is "soft off", command (on) may not have effect', + "attribute (supportedAlertActions) cannot be written", ] @@ -88,6 +92,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity): self.group = group self.controller = controller self.api: HueBridgeV2 = bridge.api + self._attr_supported_features |= SUPPORT_FLASH self._attr_supported_features |= SUPPORT_TRANSITION # Entities for Hue groups are disabled by default @@ -146,6 +151,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity): xy_color = kwargs.get(ATTR_XY_COLOR) color_temp = kwargs.get(ATTR_COLOR_TEMP) brightness = kwargs.get(ATTR_BRIGHTNESS) + flash = kwargs.get(ATTR_FLASH) if brightness is not None: # Hue uses a range of [0, 100] to control brightness. brightness = float((brightness / 255) * 100) @@ -160,6 +166,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity): and xy_color is None and color_temp is None and transition is None + and flash is None ): await self.bridge.async_request_call( self.controller.set_state, @@ -180,6 +187,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity): color_xy=xy_color if light.supports_color else None, color_temp=color_temp if light.supports_color_temperature else None, transition_time=transition, + alert=AlertEffectType.BREATHE if flash is not None else None, allowed_errors=ALLOWED_ERRORS, ) diff --git a/homeassistant/components/hue/v2/light.py b/homeassistant/components/hue/v2/light.py index de5388e1220..afb4c3d88bd 100644 --- a/homeassistant/components/hue/v2/light.py +++ b/homeassistant/components/hue/v2/light.py @@ -6,17 +6,20 @@ from typing import Any from aiohue import HueBridgeV2 from aiohue.v2.controllers.events import EventType from aiohue.v2.controllers.lights import LightsController +from aiohue.v2.models.feature import AlertEffectType from aiohue.v2.models.light import Light from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, + ATTR_FLASH, ATTR_TRANSITION, ATTR_XY_COLOR, COLOR_MODE_BRIGHTNESS, COLOR_MODE_COLOR_TEMP, COLOR_MODE_ONOFF, COLOR_MODE_XY, + SUPPORT_FLASH, SUPPORT_TRANSITION, LightEntity, ) @@ -31,6 +34,7 @@ from .entity import HueBaseEntity ALLOWED_ERRORS = [ "device (light) has communication issues, command (on) may not have effect", 'device (light) is "soft off", command (on) may not have effect', + "attribute (supportedAlertActions) cannot be written", ] @@ -68,6 +72,7 @@ class HueLight(HueBaseEntity, LightEntity): ) -> None: """Initialize the light.""" super().__init__(bridge, controller, resource) + self._attr_supported_features |= SUPPORT_FLASH self.resource = resource self.controller = controller self._supported_color_modes = set() @@ -154,6 +159,7 @@ class HueLight(HueBaseEntity, LightEntity): xy_color = kwargs.get(ATTR_XY_COLOR) color_temp = kwargs.get(ATTR_COLOR_TEMP) brightness = kwargs.get(ATTR_BRIGHTNESS) + flash = kwargs.get(ATTR_FLASH) if brightness is not None: # Hue uses a range of [0, 100] to control brightness. brightness = float((brightness / 255) * 100) @@ -169,12 +175,14 @@ class HueLight(HueBaseEntity, LightEntity): color_xy=xy_color, color_temp=color_temp, transition_time=transition, + alert=AlertEffectType.BREATHE if flash is not None else None, allowed_errors=ALLOWED_ERRORS, ) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the light off.""" transition = kwargs.get(ATTR_TRANSITION) + flash = kwargs.get(ATTR_FLASH) if transition is not None: # hue transition duration is in milliseconds transition = int(transition * 1000) @@ -183,5 +191,6 @@ class HueLight(HueBaseEntity, LightEntity): id=self.resource.id, on=False, transition_time=transition, + alert=AlertEffectType.BREATHE if flash is not None else None, allowed_errors=ALLOWED_ERRORS, ) diff --git a/tests/components/hue/test_light_v2.py b/tests/components/hue/test_light_v2.py index f2200b0c745..70a5af6d98e 100644 --- a/tests/components/hue/test_light_v2.py +++ b/tests/components/hue/test_light_v2.py @@ -121,6 +121,17 @@ async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is True assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 6000 + # test again with sending flash/alert + await hass.services.async_call( + "light", + "turn_on", + {"entity_id": test_light_id, "flash": "long"}, + blocking=True, + ) + assert len(mock_bridge_v2.mock_requests) == 3 + assert mock_bridge_v2.mock_requests[2]["json"]["on"]["on"] is True + assert mock_bridge_v2.mock_requests[2]["json"]["alert"]["action"] == "breathe" + async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_data): """Test calling the turn off service on a light.""" From 1467668c940ea59d87921fb1d4850f792b7fe9f6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 14 Dec 2021 01:23:32 +0100 Subject: [PATCH 11/25] Blacklist availability check for a light at startup in Hue integration (#61737) --- homeassistant/components/hue/v2/entity.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hue/v2/entity.py b/homeassistant/components/hue/v2/entity.py index 68c427fd3a5..ae345238c23 100644 --- a/homeassistant/components/hue/v2/entity.py +++ b/homeassistant/components/hue/v2/entity.py @@ -47,6 +47,20 @@ class HueBaseEntity(Entity): self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, self.device.id)}, ) + # some (3th party) Hue lights report their connection status incorrectly + # causing the zigbee availability to report as disconnected while in fact + # it can be controlled. Although this is in fact something the device manufacturer + # should fix, we work around it here. If the light is reported unavailable at + # startup, we ignore the availability status of the zigbee connection + self._ignore_availability = False + if self.device is None: + return + if zigbee := self.bridge.api.devices.get_zigbee_connectivity(self.device.id): + self._ignore_availability = ( + # Official Hue lights are reliable + self.device.product_data.manufacturer_name != "Signify Netherlands B.V." + and zigbee.status != ConnectivityServiceStatus.CONNECTED + ) @property def name(self) -> str: @@ -98,13 +112,12 @@ class HueBaseEntity(Entity): def available(self) -> bool: """Return entity availability.""" if self.device is None: - # devices without a device attached should be always available + # entities without a device attached should be always available return True if self.resource.type == ResourceTypes.ZIGBEE_CONNECTIVITY: # the zigbee connectivity sensor itself should be always available return True - if self.device.product_data.manufacturer_name != "Signify Netherlands B.V.": - # availability status for non-philips brand lights is unreliable + if self._ignore_availability: return True if zigbee := self.bridge.api.devices.get_zigbee_connectivity(self.device.id): # all device-attached entities get availability from the zigbee connectivity From 8cbd89282be9598c17216c1cc38fb18b686938f1 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 14 Dec 2021 01:39:51 +0100 Subject: [PATCH 12/25] Upgrade tailscale to 0.1.5 (#61744) --- homeassistant/components/tailscale/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tailscale/manifest.json b/homeassistant/components/tailscale/manifest.json index 4d47e397b76..eaa51855d38 100644 --- a/homeassistant/components/tailscale/manifest.json +++ b/homeassistant/components/tailscale/manifest.json @@ -3,7 +3,7 @@ "name": "Tailscale", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tailscale", - "requirements": ["tailscale==0.1.4"], + "requirements": ["tailscale==0.1.5"], "codeowners": ["@frenck"], "quality_scale": "platinum", "iot_class": "cloud_polling" diff --git a/requirements_all.txt b/requirements_all.txt index 775246eb32d..7c884b9168d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2272,7 +2272,7 @@ systembridge==2.2.3 tahoma-api==0.0.16 # homeassistant.components.tailscale -tailscale==0.1.4 +tailscale==0.1.5 # homeassistant.components.tank_utility tank_utility==1.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index fa589181636..00aeb5239aa 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1352,7 +1352,7 @@ surepy==0.7.2 systembridge==2.2.3 # homeassistant.components.tailscale -tailscale==0.1.4 +tailscale==0.1.5 # homeassistant.components.tellduslive tellduslive==0.10.11 From ffe84e8ece131c113275acdd422c9869e8836c07 Mon Sep 17 00:00:00 2001 From: Eduard van Valkenburg Date: Tue, 14 Dec 2021 13:01:30 +0100 Subject: [PATCH 13/25] Bump brunt package to 1.0.1 (#61784) --- homeassistant/components/brunt/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/brunt/manifest.json b/homeassistant/components/brunt/manifest.json index 976b017ca09..1ddbbb62f56 100644 --- a/homeassistant/components/brunt/manifest.json +++ b/homeassistant/components/brunt/manifest.json @@ -3,7 +3,7 @@ "name": "Brunt Blind Engine", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/brunt", - "requirements": ["brunt==1.0.0"], + "requirements": ["brunt==1.0.1"], "codeowners": ["@eavanvalkenburg"], "iot_class": "cloud_polling" } diff --git a/requirements_all.txt b/requirements_all.txt index 7c884b9168d..900e28d0bd1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -440,7 +440,7 @@ brother==1.1.0 brottsplatskartan==0.0.1 # homeassistant.components.brunt -brunt==1.0.0 +brunt==1.0.1 # homeassistant.components.bsblan bsblan==0.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 00aeb5239aa..0c6e826e221 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -281,7 +281,7 @@ broadlink==0.18.0 brother==1.1.0 # homeassistant.components.brunt -brunt==1.0.0 +brunt==1.0.1 # homeassistant.components.bsblan bsblan==0.4.0 From 34568aad89f3bfa67d9ad8dbe48d12c6039535fc Mon Sep 17 00:00:00 2001 From: MattWestb <49618193+MattWestb@users.noreply.github.com> Date: Tue, 14 Dec 2021 14:49:00 +0100 Subject: [PATCH 14/25] Fix ZHA unoccupied setpoints. (#61791) ATTR_UNOCCP_HEAT_SETPT and ATTR_UNOCCP_COOL_SETPT is mixed up. Fixing so heating is heating and cooling is colling. --- homeassistant/components/zha/climate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zha/climate.py b/homeassistant/components/zha/climate.py index f7a1d1815db..d57fb21b4a3 100644 --- a/homeassistant/components/zha/climate.py +++ b/homeassistant/components/zha/climate.py @@ -206,11 +206,11 @@ class Thermostat(ZhaEntity, ClimateEntity): unoccupied_cooling_setpoint = self._thrm.unoccupied_cooling_setpoint if unoccupied_cooling_setpoint is not None: - data[ATTR_UNOCCP_HEAT_SETPT] = unoccupied_cooling_setpoint + data[ATTR_UNOCCP_COOL_SETPT] = unoccupied_cooling_setpoint unoccupied_heating_setpoint = self._thrm.unoccupied_heating_setpoint if unoccupied_heating_setpoint is not None: - data[ATTR_UNOCCP_COOL_SETPT] = unoccupied_heating_setpoint + data[ATTR_UNOCCP_HEAT_SETPT] = unoccupied_heating_setpoint return data @property From 40f76d4ed95e618789fab18f5118cbfd88b54f10 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 15 Dec 2021 10:40:37 +0100 Subject: [PATCH 15/25] Don't override pychromecast MediaController's APP ID (#61796) --- homeassistant/components/cast/media_player.py | 8 +--- tests/components/cast/test_media_player.py | 43 +++++++++++++++---- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 46c25501f3a..61922a4cd8b 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -47,7 +47,6 @@ from homeassistant.components.plex.const import PLEX_URI_SCHEME from homeassistant.components.plex.services import lookup_plex_media from homeassistant.const import ( CAST_APP_ID_HOMEASSISTANT_LOVELACE, - CAST_APP_ID_HOMEASSISTANT_MEDIA, EVENT_HOMEASSISTANT_STOP, STATE_IDLE, STATE_OFF, @@ -230,7 +229,6 @@ class CastDevice(MediaPlayerEntity): self._cast_info.cast_info, ChromeCastZeroconf.get_zeroconf(), ) - chromecast.media_controller.app_id = CAST_APP_ID_HOMEASSISTANT_MEDIA self._chromecast = chromecast if CAST_MULTIZONE_MANAGER_KEY not in self.hass.data: @@ -527,9 +525,8 @@ class CastDevice(MediaPlayerEntity): self._chromecast.register_handler(controller) controller.play_media(media) else: - self._chromecast.media_controller.play_media( - media_id, media_type, **kwargs.get(ATTR_MEDIA_EXTRA, {}) - ) + app_data = {"media_id": media_id, "media_type": media_type, **extra} + quick_play(self._chromecast, "homeassistant_media", app_data) def _media_status(self): """ @@ -820,7 +817,6 @@ class DynamicCastGroup: self._cast_info.cast_info, ChromeCastZeroconf.get_zeroconf(), ) - chromecast.media_controller.app_id = CAST_APP_ID_HOMEASSISTANT_MEDIA self._chromecast = chromecast if CAST_MULTIZONE_MANAGER_KEY not in self.hass.data: diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index adab55c50df..85562f39761 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -754,7 +754,7 @@ async def test_supported_features( assert state.attributes.get("supported_features") == supported_features -async def test_entity_play_media(hass: HomeAssistant): +async def test_entity_play_media(hass: HomeAssistant, quick_play_mock): """Test playing media.""" entity_id = "media_player.speaker" reg = er.async_get(hass) @@ -776,8 +776,28 @@ async def test_entity_play_media(hass: HomeAssistant): assert entity_id == reg.async_get_entity_id("media_player", "cast", str(info.uuid)) # Play_media - await common.async_play_media(hass, "audio", "best.mp3", entity_id) - chromecast.media_controller.play_media.assert_called_once_with("best.mp3", "audio") + await hass.services.async_call( + media_player.DOMAIN, + media_player.SERVICE_PLAY_MEDIA, + { + ATTR_ENTITY_ID: entity_id, + media_player.ATTR_MEDIA_CONTENT_TYPE: "audio", + media_player.ATTR_MEDIA_CONTENT_ID: "best.mp3", + media_player.ATTR_MEDIA_EXTRA: {"metadata": {"metadatatype": 3}}, + }, + blocking=True, + ) + + chromecast.media_controller.play_media.assert_not_called() + quick_play_mock.assert_called_once_with( + chromecast, + "homeassistant_media", + { + "media_id": "best.mp3", + "media_type": "audio", + "metadata": {"metadatatype": 3}, + }, + ) async def test_entity_play_media_cast(hass: HomeAssistant, quick_play_mock): @@ -865,7 +885,7 @@ async def test_entity_play_media_cast_invalid(hass, caplog, quick_play_mock): assert "App unknown not supported" in caplog.text -async def test_entity_play_media_sign_URL(hass: HomeAssistant): +async def test_entity_play_media_sign_URL(hass: HomeAssistant, quick_play_mock): """Test playing media.""" entity_id = "media_player.speaker" @@ -886,8 +906,10 @@ async def test_entity_play_media_sign_URL(hass: HomeAssistant): # Play_media await common.async_play_media(hass, "audio", "/best.mp3", entity_id) - chromecast.media_controller.play_media.assert_called_once_with(ANY, "audio") - assert chromecast.media_controller.play_media.call_args[0][0].startswith( + quick_play_mock.assert_called_once_with( + chromecast, "homeassistant_media", {"media_id": ANY, "media_type": "audio"} + ) + assert quick_play_mock.call_args[0][2]["media_id"].startswith( "http://example.com:8123/best.mp3?authSig=" ) @@ -1231,7 +1253,7 @@ async def test_group_media_states(hass, mz_mock): assert state.state == "playing" -async def test_group_media_control(hass, mz_mock): +async def test_group_media_control(hass, mz_mock, quick_play_mock): """Test media controls are handled by group if entity has no state.""" entity_id = "media_player.speaker" reg = er.async_get(hass) @@ -1286,7 +1308,12 @@ async def test_group_media_control(hass, mz_mock): # Verify play_media is not forwarded await common.async_play_media(hass, "music", "best.mp3", entity_id) assert not grp_media.play_media.called - assert chromecast.media_controller.play_media.called + assert not chromecast.media_controller.play_media.called + quick_play_mock.assert_called_once_with( + chromecast, + "homeassistant_media", + {"media_id": "best.mp3", "media_type": "music"}, + ) async def test_failed_cast_on_idle(hass, caplog): From 32bdcdd663af1d67f8df673b0fd8ee6e1a036b93 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 15 Dec 2021 10:40:06 +0100 Subject: [PATCH 16/25] Bump pychromecast to 10.2.1 (#61811) --- homeassistant/components/cast/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/cast/manifest.json b/homeassistant/components/cast/manifest.json index 3f3c31b8d3d..bee18948a33 100644 --- a/homeassistant/components/cast/manifest.json +++ b/homeassistant/components/cast/manifest.json @@ -3,7 +3,7 @@ "name": "Google Cast", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/cast", - "requirements": ["pychromecast==10.1.1"], + "requirements": ["pychromecast==10.2.1"], "after_dependencies": [ "cloud", "http", diff --git a/requirements_all.txt b/requirements_all.txt index 900e28d0bd1..04a35c673c3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1396,7 +1396,7 @@ pycfdns==1.2.2 pychannels==1.0.0 # homeassistant.components.cast -pychromecast==10.1.1 +pychromecast==10.2.1 # homeassistant.components.pocketcasts pycketcasts==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0c6e826e221..7dff2d9a1e6 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -850,7 +850,7 @@ pybotvac==0.0.22 pycfdns==1.2.2 # homeassistant.components.cast -pychromecast==10.1.1 +pychromecast==10.2.1 # homeassistant.components.climacell pyclimacell==0.18.2 From b51330136321e4cce7daa3cb6526c70b3be8b665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hjelseth=20H=C3=B8yer?= Date: Tue, 14 Dec 2021 18:40:47 +0100 Subject: [PATCH 17/25] Tibber, update library, fixes #61525 (#61813) --- homeassistant/components/tibber/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index a653e91b991..c0b047a2856 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -2,7 +2,7 @@ "domain": "tibber", "name": "Tibber", "documentation": "https://www.home-assistant.io/integrations/tibber", - "requirements": ["pyTibber==0.21.0"], + "requirements": ["pyTibber==0.21.1"], "codeowners": ["@danielhiversen"], "quality_scale": "silver", "config_flow": true, diff --git a/requirements_all.txt b/requirements_all.txt index 04a35c673c3..451fc9b9c3a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1327,7 +1327,7 @@ pyRFXtrx==0.27.0 # pySwitchmate==0.4.6 # homeassistant.components.tibber -pyTibber==0.21.0 +pyTibber==0.21.1 # homeassistant.components.dlink pyW215==0.7.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7dff2d9a1e6..b0de95305ab 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -808,7 +808,7 @@ pyMetno==0.9.0 pyRFXtrx==0.27.0 # homeassistant.components.tibber -pyTibber==0.21.0 +pyTibber==0.21.1 # homeassistant.components.nextbus py_nextbusnext==0.1.5 From 1faa111222f4fcceb41ed02db71f7fc2c8092333 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Tue, 14 Dec 2021 22:36:55 +0100 Subject: [PATCH 18/25] Bump python-miio to 0.5.9.2 (#61831) --- homeassistant/components/xiaomi_miio/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/xiaomi_miio/manifest.json b/homeassistant/components/xiaomi_miio/manifest.json index 757fca8be1f..8de844cdd44 100644 --- a/homeassistant/components/xiaomi_miio/manifest.json +++ b/homeassistant/components/xiaomi_miio/manifest.json @@ -3,7 +3,7 @@ "name": "Xiaomi Miio", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/xiaomi_miio", - "requirements": ["construct==2.10.56", "micloud==0.4", "python-miio==0.5.9.1"], + "requirements": ["construct==2.10.56", "micloud==0.4", "python-miio==0.5.9.2"], "codeowners": ["@rytilahti", "@syssi", "@starkillerOG", "@bieniu"], "zeroconf": ["_miio._udp.local."], "iot_class": "local_polling" diff --git a/requirements_all.txt b/requirements_all.txt index 451fc9b9c3a..3a403b690a6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1904,7 +1904,7 @@ python-kasa==0.4.0 # python-lirc==1.2.3 # homeassistant.components.xiaomi_miio -python-miio==0.5.9.1 +python-miio==0.5.9.2 # homeassistant.components.mpd python-mpd2==3.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b0de95305ab..b07994d9b92 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1145,7 +1145,7 @@ python-juicenet==1.0.2 python-kasa==0.4.0 # homeassistant.components.xiaomi_miio -python-miio==0.5.9.1 +python-miio==0.5.9.2 # homeassistant.components.nest python-nest==4.1.0 From 77b1df59022f7f84c8894c0330aa176eb45d5da2 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Wed, 15 Dec 2021 05:17:09 -0700 Subject: [PATCH 19/25] Ensure SimpliSafe websocket reconnects upon new token (#61835) --- homeassistant/components/simplisafe/__init__.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/simplisafe/__init__.py b/homeassistant/components/simplisafe/__init__.py index cd04de5d34c..dd3ff717e28 100644 --- a/homeassistant/components/simplisafe/__init__.py +++ b/homeassistant/components/simplisafe/__init__.py @@ -612,10 +612,24 @@ class SimpliSafe: data={**self.entry.data, CONF_TOKEN: token}, ) + @callback + def async_handle_refresh_token(token: str) -> None: + """Handle a new refresh token.""" + async_save_refresh_token(token) + + if TYPE_CHECKING: + assert self._api.websocket + + if self._api.websocket.connected: + # If a websocket connection is open, reconnect it to use the + # new access token: + asyncio.create_task(self._api.websocket.async_reconnect()) + self.entry.async_on_unload( - self._api.add_refresh_token_callback(async_save_refresh_token) + self._api.add_refresh_token_callback(async_handle_refresh_token) ) + # Save the refresh token we got on entry setup: async_save_refresh_token(self._api.refresh_token) async def async_update(self) -> None: From f271fea07c413cb5404dab4848fc4a235901d482 Mon Sep 17 00:00:00 2001 From: Marvin Wichmann Date: Wed, 15 Dec 2021 13:15:56 +0100 Subject: [PATCH 20/25] Allow setting local_ip for knx routing connections (#61836) --- homeassistant/components/knx/__init__.py | 1 + homeassistant/components/knx/config_flow.py | 19 ++++- homeassistant/components/knx/strings.json | 7 +- .../components/knx/translations/en.json | 5 +- tests/components/knx/test_config_flow.py | 64 ++++++++++++++- tests/components/knx/test_init.py | 78 +++++++++++++++++++ 6 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 tests/components/knx/test_init.py diff --git a/homeassistant/components/knx/__init__.py b/homeassistant/components/knx/__init__.py index ba6689a023d..5a66824fbcb 100644 --- a/homeassistant/components/knx/__init__.py +++ b/homeassistant/components/knx/__init__.py @@ -383,6 +383,7 @@ class KNXModule: if _conn_type == CONF_KNX_ROUTING: return ConnectionConfig( connection_type=ConnectionType.ROUTING, + local_ip=self.config.get(ConnectionSchema.CONF_KNX_LOCAL_IP), auto_reconnect=True, ) if _conn_type == CONF_KNX_TUNNELING: diff --git a/homeassistant/components/knx/config_flow.py b/homeassistant/components/knx/config_flow.py index 30071752731..96aa8f67e3b 100644 --- a/homeassistant/components/knx/config_flow.py +++ b/homeassistant/components/knx/config_flow.py @@ -137,9 +137,11 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): vol.Required( ConnectionSchema.CONF_KNX_ROUTE_BACK, default=False ): vol.Coerce(bool), - vol.Optional(ConnectionSchema.CONF_KNX_LOCAL_IP): str, } + if self.show_advanced_options: + fields[vol.Optional(ConnectionSchema.CONF_KNX_LOCAL_IP)] = str + return self.async_show_form( step_id="manual_tunnel", data_schema=vol.Schema(fields), errors=errors ) @@ -195,6 +197,9 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): CONF_KNX_INDIVIDUAL_ADDRESS: user_input[ CONF_KNX_INDIVIDUAL_ADDRESS ], + ConnectionSchema.CONF_KNX_LOCAL_IP: user_input.get( + ConnectionSchema.CONF_KNX_LOCAL_IP + ), CONF_KNX_CONNECTION_TYPE: CONF_KNX_ROUTING, }, ) @@ -211,6 +216,9 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): ): cv.port, } + if self.show_advanced_options: + fields[vol.Optional(ConnectionSchema.CONF_KNX_LOCAL_IP)] = str + return self.async_show_form( step_id="routing", data_schema=vol.Schema(fields), errors=errors ) @@ -306,7 +314,6 @@ class KNXOptionsFlowHandler(OptionsFlow): vol.Required( CONF_PORT, default=self.current_config.get(CONF_PORT, 3671) ): cv.port, - vol.Optional(ConnectionSchema.CONF_KNX_LOCAL_IP): str, vol.Required( ConnectionSchema.CONF_KNX_ROUTE_BACK, default=self.current_config.get( @@ -381,6 +388,14 @@ class KNXOptionsFlowHandler(OptionsFlow): } if self.show_advanced_options: + data_schema[ + vol.Optional( + ConnectionSchema.CONF_KNX_LOCAL_IP, + default=self.current_config.get( + ConnectionSchema.CONF_KNX_LOCAL_IP, + ), + ) + ] = str data_schema[ vol.Required( ConnectionSchema.CONF_KNX_STATE_UPDATER, diff --git a/homeassistant/components/knx/strings.json b/homeassistant/components/knx/strings.json index 7f770c25427..4db92888aab 100644 --- a/homeassistant/components/knx/strings.json +++ b/homeassistant/components/knx/strings.json @@ -28,7 +28,8 @@ "data": { "individual_address": "Individual address for the routing connection", "multicast_group": "The multicast group used for routing", - "multicast_port": "The multicast port used for routing" + "multicast_port": "The multicast port used for routing", + "local_ip": "Local IP (leave empty if unsure)" } } }, @@ -48,6 +49,7 @@ "individual_address": "Default individual address", "multicast_group": "Multicast group used for routing and discovery", "multicast_port": "Multicast port used for routing and discovery", + "local_ip": "Local IP (leave empty if unsure)", "state_updater": "Globally enable reading states from the KNX Bus", "rate_limit": "Maximum outgoing telegrams per second" } @@ -56,8 +58,7 @@ "data": { "port": "[%key:common::config_flow::data::port%]", "host": "[%key:common::config_flow::data::host%]", - "route_back": "Route Back / NAT Mode", - "local_ip": "Local IP (leave empty if unsure)" + "route_back": "Route Back / NAT Mode" } } } diff --git a/homeassistant/components/knx/translations/en.json b/homeassistant/components/knx/translations/en.json index 5320f0cfb03..91b9dfce5f3 100644 --- a/homeassistant/components/knx/translations/en.json +++ b/homeassistant/components/knx/translations/en.json @@ -22,7 +22,8 @@ "data": { "individual_address": "Individual address for the routing connection", "multicast_group": "The multicast group used for routing", - "multicast_port": "The multicast port used for routing" + "multicast_port": "The multicast port used for routing", + "local_ip": "Local IP (leave empty if unsure)" }, "description": "Please configure the routing options." }, @@ -48,6 +49,7 @@ "individual_address": "Default individual address", "multicast_group": "Multicast group used for routing and discovery", "multicast_port": "Multicast port used for routing and discovery", + "local_ip": "Local IP (leave empty if unsure)", "rate_limit": "Maximum outgoing telegrams per second", "state_updater": "Globally enable reading states from the KNX Bus" } @@ -55,7 +57,6 @@ "tunnel": { "data": { "host": "Host", - "local_ip": "Local IP (leave empty if unsure)", "port": "Port", "route_back": "Route Back / NAT Mode" } diff --git a/tests/components/knx/test_config_flow.py b/tests/components/knx/test_config_flow.py index ff1fc362aa5..65289c2b173 100644 --- a/tests/components/knx/test_config_flow.py +++ b/tests/components/knx/test_config_flow.py @@ -83,6 +83,60 @@ async def test_routing_setup(hass: HomeAssistant) -> None: CONF_KNX_CONNECTION_TYPE: CONF_KNX_ROUTING, ConnectionSchema.CONF_KNX_MCAST_GRP: DEFAULT_MCAST_GRP, ConnectionSchema.CONF_KNX_MCAST_PORT: 3675, + ConnectionSchema.CONF_KNX_LOCAL_IP: None, + CONF_KNX_INDIVIDUAL_ADDRESS: "1.1.110", + } + + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_routing_setup_advanced(hass: HomeAssistant) -> None: + """Test routing setup with advanced options.""" + with patch("xknx.io.gateway_scanner.GatewayScanner.scan") as gateways: + gateways.return_value = [] + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={ + "source": config_entries.SOURCE_USER, + "show_advanced_options": True, + }, + ) + assert result["type"] == RESULT_TYPE_FORM + assert not result["errors"] + + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_KNX_CONNECTION_TYPE: CONF_KNX_ROUTING, + }, + ) + await hass.async_block_till_done() + assert result2["type"] == RESULT_TYPE_FORM + assert result2["step_id"] == "routing" + assert not result2["errors"] + + with patch( + "homeassistant.components.knx.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result3 = await hass.config_entries.flow.async_configure( + result2["flow_id"], + { + ConnectionSchema.CONF_KNX_MCAST_GRP: DEFAULT_MCAST_GRP, + ConnectionSchema.CONF_KNX_MCAST_PORT: 3675, + CONF_KNX_INDIVIDUAL_ADDRESS: "1.1.110", + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", + }, + ) + await hass.async_block_till_done() + assert result3["type"] == RESULT_TYPE_CREATE_ENTRY + assert result3["title"] == CONF_KNX_ROUTING.capitalize() + assert result3["data"] == { + **DEFAULT_ENTRY_DATA, + CONF_KNX_CONNECTION_TYPE: CONF_KNX_ROUTING, + ConnectionSchema.CONF_KNX_MCAST_GRP: DEFAULT_MCAST_GRP, + ConnectionSchema.CONF_KNX_MCAST_PORT: 3675, + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", CONF_KNX_INDIVIDUAL_ADDRESS: "1.1.110", } @@ -144,7 +198,11 @@ async def test_tunneling_setup_for_local_ip(hass: HomeAssistant) -> None: with patch("xknx.io.gateway_scanner.GatewayScanner.scan") as gateways: gateways.return_value = [gateway] result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} + DOMAIN, + context={ + "source": config_entries.SOURCE_USER, + "show_advanced_options": True, + }, ) assert result["type"] == RESULT_TYPE_FORM assert not result["errors"] @@ -563,7 +621,6 @@ async def test_tunneling_options_flow( CONF_HOST: "192.168.1.1", CONF_PORT: 3675, ConnectionSchema.CONF_KNX_ROUTE_BACK: True, - ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", }, ) @@ -581,7 +638,6 @@ async def test_tunneling_options_flow( CONF_HOST: "192.168.1.1", CONF_PORT: 3675, ConnectionSchema.CONF_KNX_ROUTE_BACK: True, - ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", } @@ -611,6 +667,7 @@ async def test_advanced_options( ConnectionSchema.CONF_KNX_MCAST_GRP: DEFAULT_MCAST_GRP, ConnectionSchema.CONF_KNX_RATE_LIMIT: 25, ConnectionSchema.CONF_KNX_STATE_UPDATER: False, + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", }, ) @@ -626,4 +683,5 @@ async def test_advanced_options( ConnectionSchema.CONF_KNX_MCAST_GRP: DEFAULT_MCAST_GRP, ConnectionSchema.CONF_KNX_RATE_LIMIT: 25, ConnectionSchema.CONF_KNX_STATE_UPDATER: False, + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", } diff --git a/tests/components/knx/test_init.py b/tests/components/knx/test_init.py new file mode 100644 index 00000000000..4380b132cbd --- /dev/null +++ b/tests/components/knx/test_init.py @@ -0,0 +1,78 @@ +"""Test KNX init.""" +import pytest +from xknx import XKNX +from xknx.io import ConnectionConfig, ConnectionType + +from homeassistant.components.knx.const import ( + CONF_KNX_AUTOMATIC, + CONF_KNX_CONNECTION_TYPE, + CONF_KNX_INDIVIDUAL_ADDRESS, + CONF_KNX_ROUTING, + CONF_KNX_TUNNELING, + DOMAIN as KNX_DOMAIN, +) +from homeassistant.components.knx.schema import ConnectionSchema +from homeassistant.const import CONF_HOST, CONF_PORT +from homeassistant.core import HomeAssistant + +from .conftest import KNXTestKit + +from tests.common import MockConfigEntry + + +@pytest.mark.parametrize( + "config_entry_data,connection_config", + [ + ( + { + CONF_KNX_INDIVIDUAL_ADDRESS: XKNX.DEFAULT_ADDRESS, + CONF_KNX_CONNECTION_TYPE: CONF_KNX_AUTOMATIC, + }, + ConnectionConfig(), + ), + ( + { + CONF_KNX_CONNECTION_TYPE: CONF_KNX_ROUTING, + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.1", + }, + ConnectionConfig( + connection_type=ConnectionType.ROUTING, local_ip="192.168.1.1" + ), + ), + ( + { + CONF_KNX_CONNECTION_TYPE: CONF_KNX_TUNNELING, + CONF_HOST: "192.168.0.2", + CONF_PORT: 3675, + ConnectionSchema.CONF_KNX_ROUTE_BACK: False, + ConnectionSchema.CONF_KNX_LOCAL_IP: "192.168.1.112", + }, + ConnectionConfig( + connection_type=ConnectionType.TUNNELING, + route_back=False, + gateway_ip="192.168.0.2", + gateway_port=3675, + local_ip="192.168.1.112", + auto_reconnect=True, + ), + ), + ], +) +async def test_init_connection_handling( + hass: HomeAssistant, knx: KNXTestKit, config_entry_data, connection_config +): + """Test correctly generating connection config.""" + + config_entry = MockConfigEntry( + title="KNX", + domain=KNX_DOMAIN, + data=config_entry_data, + ) + knx.mock_config_entry = config_entry + await knx.setup_integration({}) + + assert hass.data.get(KNX_DOMAIN) is not None + + assert ( + hass.data[KNX_DOMAIN].connection_config().__dict__ == connection_config.__dict__ + ) From 686f6768fcab2051aa14856fb02a3fd2b1a47770 Mon Sep 17 00:00:00 2001 From: Michael Davie Date: Wed, 15 Dec 2021 07:13:59 -0500 Subject: [PATCH 21/25] Fix broken Environment Canada (#61848) --- homeassistant/components/environment_canada/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/environment_canada/manifest.json b/homeassistant/components/environment_canada/manifest.json index b340674b480..868e62f07c3 100644 --- a/homeassistant/components/environment_canada/manifest.json +++ b/homeassistant/components/environment_canada/manifest.json @@ -2,7 +2,7 @@ "domain": "environment_canada", "name": "Environment Canada", "documentation": "https://www.home-assistant.io/integrations/environment_canada", - "requirements": ["env_canada==0.5.18"], + "requirements": ["env_canada==0.5.20"], "codeowners": ["@gwww", "@michaeldavie"], "config_flow": true, "iot_class": "cloud_polling" diff --git a/requirements_all.txt b/requirements_all.txt index 3a403b690a6..638c8e4f353 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -600,7 +600,7 @@ enocean==0.50 enturclient==0.2.2 # homeassistant.components.environment_canada -env_canada==0.5.18 +env_canada==0.5.20 # homeassistant.components.envirophat # envirophat==0.0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b07994d9b92..0d23c6d8706 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -375,7 +375,7 @@ emulated_roku==0.2.1 enocean==0.50 # homeassistant.components.environment_canada -env_canada==0.5.18 +env_canada==0.5.20 # homeassistant.components.enphase_envoy envoy_reader==0.20.1 From 86622794e0027ccc1628999bafca944edb5472ff Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Wed, 15 Dec 2021 04:12:38 -0800 Subject: [PATCH 22/25] Bump google-nest-sdm to 0.4.8 (#61851) --- homeassistant/components/nest/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/nest/test_events.py | 115 ++++++++++++++++---- 4 files changed, 98 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/nest/manifest.json b/homeassistant/components/nest/manifest.json index 507711c73ff..0c14e59babc 100644 --- a/homeassistant/components/nest/manifest.json +++ b/homeassistant/components/nest/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "dependencies": ["ffmpeg", "http", "media_source"], "documentation": "https://www.home-assistant.io/integrations/nest", - "requirements": ["python-nest==4.1.0", "google-nest-sdm==0.4.6"], + "requirements": ["python-nest==4.1.0", "google-nest-sdm==0.4.8"], "codeowners": ["@allenporter"], "quality_scale": "platinum", "dhcp": [ diff --git a/requirements_all.txt b/requirements_all.txt index 638c8e4f353..b179629589c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,7 +738,7 @@ google-cloud-pubsub==2.1.0 google-cloud-texttospeech==0.4.0 # homeassistant.components.nest -google-nest-sdm==0.4.6 +google-nest-sdm==0.4.8 # homeassistant.components.google_travel_time googlemaps==2.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0d23c6d8706..b39b82b89f4 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -461,7 +461,7 @@ google-api-python-client==1.6.4 google-cloud-pubsub==2.1.0 # homeassistant.components.nest -google-nest-sdm==0.4.6 +google-nest-sdm==0.4.8 # homeassistant.components.google_travel_time googlemaps==2.5.1 diff --git a/tests/components/nest/test_events.py b/tests/components/nest/test_events.py index 4767fd815d2..4a625999155 100644 --- a/tests/components/nest/test_events.py +++ b/tests/components/nest/test_events.py @@ -39,13 +39,12 @@ async def async_setup_devices(hass, device_type, traits={}): return await async_setup_sdm_platform(hass, PLATFORM, devices=devices) -def create_device_traits(event_trait): +def create_device_traits(event_traits=[]): """Create fake traits for a device.""" - return { + result = { "sdm.devices.traits.Info": { "customName": "Front", }, - event_trait: {}, "sdm.devices.traits.CameraLiveStream": { "maxVideoResolution": { "width": 640, @@ -55,6 +54,8 @@ def create_device_traits(event_trait): "audioCodecs": ["AAC"], }, } + result.update({t: {} for t in event_traits}) + return result def create_event(event_type, device_id=DEVICE_ID, timestamp=None): @@ -91,7 +92,7 @@ async def test_doorbell_chime_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.DoorbellChime"), + create_device_traits(["sdm.devices.traits.DoorbellChime"]), ) registry = er.async_get(hass) @@ -129,7 +130,7 @@ async def test_camera_motion_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.CAMERA", - create_device_traits("sdm.devices.traits.CameraMotion"), + create_device_traits(["sdm.devices.traits.CameraMotion"]), ) registry = er.async_get(hass) entry = registry.async_get("camera.front") @@ -157,7 +158,7 @@ async def test_camera_sound_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.CAMERA", - create_device_traits("sdm.devices.traits.CameraSound"), + create_device_traits(["sdm.devices.traits.CameraSound"]), ) registry = er.async_get(hass) entry = registry.async_get("camera.front") @@ -185,7 +186,7 @@ async def test_camera_person_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.CameraEventImage"), + create_device_traits(["sdm.devices.traits.CameraPerson"]), ) registry = er.async_get(hass) entry = registry.async_get("camera.front") @@ -213,7 +214,9 @@ async def test_camera_multiple_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.CameraEventImage"), + create_device_traits( + ["sdm.devices.traits.CameraMotion", "sdm.devices.traits.CameraPerson"] + ), ) registry = er.async_get(hass) entry = registry.async_get("camera.front") @@ -256,7 +259,7 @@ async def test_unknown_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.DoorbellChime"), + create_device_traits(["sdm.devices.traits.DoorbellChime"]), ) await subscriber.async_receive_event(create_event("some-event-id")) await hass.async_block_till_done() @@ -270,7 +273,7 @@ async def test_unknown_device_id(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.DoorbellChime"), + create_device_traits(["sdm.devices.traits.DoorbellChime"]), ) await subscriber.async_receive_event( create_event("sdm.devices.events.DoorbellChime.Chime", "invalid-device-id") @@ -286,7 +289,7 @@ async def test_event_message_without_device_event(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - create_device_traits("sdm.devices.traits.DoorbellChime"), + create_device_traits(["sdm.devices.traits.DoorbellChime"]), ) timestamp = utcnow() event = EventMessage( @@ -308,14 +311,12 @@ async def test_doorbell_event_thread(hass): subscriber = await async_setup_devices( hass, "sdm.devices.types.DOORBELL", - traits={ - "sdm.devices.traits.Info": { - "customName": "Front", - }, - "sdm.devices.traits.CameraLiveStream": {}, - "sdm.devices.traits.CameraClipPreview": {}, - "sdm.devices.traits.CameraPerson": {}, - }, + create_device_traits( + [ + "sdm.devices.traits.CameraClipPreview", + "sdm.devices.traits.CameraPerson", + ] + ), ) registry = er.async_get(hass) entry = registry.async_get("camera.front") @@ -351,7 +352,7 @@ async def test_doorbell_event_thread(hass): ) await subscriber.async_receive_event(EventMessage(message_data_1, auth=None)) - # Publish message #1 that sends a no-op update to end the event thread + # Publish message #2 that sends a no-op update to end the event thread timestamp2 = timestamp1 + datetime.timedelta(seconds=1) message_data_2 = event_message_data.copy() message_data_2.update( @@ -371,3 +372,77 @@ async def test_doorbell_event_thread(hass): "timestamp": timestamp1.replace(microsecond=0), "nest_event_id": EVENT_SESSION_ID, } + + +async def test_doorbell_event_session_update(hass): + """Test a pubsub message with updates to an existing session.""" + events = async_capture_events(hass, NEST_EVENT) + subscriber = await async_setup_devices( + hass, + "sdm.devices.types.DOORBELL", + create_device_traits( + [ + "sdm.devices.traits.CameraClipPreview", + "sdm.devices.traits.CameraPerson", + "sdm.devices.traits.CameraMotion", + ] + ), + ) + registry = er.async_get(hass) + entry = registry.async_get("camera.front") + assert entry is not None + + # Message #1 has a motion event + timestamp1 = utcnow() + await subscriber.async_receive_event( + create_events( + { + "sdm.devices.events.CameraMotion.Motion": { + "eventSessionId": EVENT_SESSION_ID, + "eventId": "n:1", + }, + "sdm.devices.events.CameraClipPreview.ClipPreview": { + "eventSessionId": EVENT_SESSION_ID, + "previewUrl": "image-url-1", + }, + }, + timestamp=timestamp1, + ) + ) + + # Message #2 has an extra person event + timestamp2 = utcnow() + await subscriber.async_receive_event( + create_events( + { + "sdm.devices.events.CameraMotion.Motion": { + "eventSessionId": EVENT_SESSION_ID, + "eventId": "n:1", + }, + "sdm.devices.events.CameraPerson.Person": { + "eventSessionId": EVENT_SESSION_ID, + "eventId": "n:2", + }, + "sdm.devices.events.CameraClipPreview.ClipPreview": { + "eventSessionId": EVENT_SESSION_ID, + "previewUrl": "image-url-1", + }, + }, + timestamp=timestamp2, + ) + ) + await hass.async_block_till_done() + + assert len(events) == 2 + assert events[0].data == { + "device_id": entry.device_id, + "type": "camera_motion", + "timestamp": timestamp1.replace(microsecond=0), + "nest_event_id": EVENT_SESSION_ID, + } + assert events[1].data == { + "device_id": entry.device_id, + "type": "camera_person", + "timestamp": timestamp2.replace(microsecond=0), + "nest_event_id": EVENT_SESSION_ID, + } From 2772bae2e1271c975d758e0f2c65655addef3560 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Wed, 15 Dec 2021 12:15:05 +0100 Subject: [PATCH 23/25] Bump aiohue to 3.0.5 (#61875) --- homeassistant/components/hue/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json index 7f424f14594..f32d8edc284 100644 --- a/homeassistant/components/hue/manifest.json +++ b/homeassistant/components/hue/manifest.json @@ -3,7 +3,7 @@ "name": "Philips Hue", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/hue", - "requirements": ["aiohue==3.0.4"], + "requirements": ["aiohue==3.0.5"], "ssdp": [ { "manufacturer": "Royal Philips Electronics", diff --git a/requirements_all.txt b/requirements_all.txt index b179629589c..d792fa1afc8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -186,7 +186,7 @@ aiohomekit==0.6.4 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==3.0.4 +aiohue==3.0.5 # homeassistant.components.imap aioimaplib==0.9.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b39b82b89f4..d707eaa5d34 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -131,7 +131,7 @@ aiohomekit==0.6.4 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==3.0.4 +aiohue==3.0.5 # homeassistant.components.apache_kafka aiokafka==0.6.0 From e7e20533bd6f78f35b816cd784e67516b3d8f587 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 15 Dec 2021 15:15:47 +0100 Subject: [PATCH 24/25] Update frontend to 20211215.0 (#61877) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 4380440408f..4ac95c38afc 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", "requirements": [ - "home-assistant-frontend==20211212.0" + "home-assistant-frontend==20211215.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 6c86e5804d8..e52542ccea0 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -16,7 +16,7 @@ ciso8601==2.2.0 cryptography==35.0.0 emoji==1.5.0 hass-nabucasa==0.50.0 -home-assistant-frontend==20211212.0 +home-assistant-frontend==20211215.0 httpx==0.21.0 ifaddr==0.1.7 jinja2==3.0.3 diff --git a/requirements_all.txt b/requirements_all.txt index d792fa1afc8..0631714600b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -819,7 +819,7 @@ hole==0.7.0 holidays==0.11.3.1 # homeassistant.components.frontend -home-assistant-frontend==20211212.0 +home-assistant-frontend==20211215.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d707eaa5d34..780a343463f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -515,7 +515,7 @@ hole==0.7.0 holidays==0.11.3.1 # homeassistant.components.frontend -home-assistant-frontend==20211212.0 +home-assistant-frontend==20211215.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 From ac2897fc67a9c78b2f443ff5ff7bd99a9ccc312b Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 15 Dec 2021 16:04:48 +0100 Subject: [PATCH 25/25] Bumped version to 2021.12.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 00e2b23df4e..6fd2760d618 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -7,7 +7,7 @@ from homeassistant.backports.enum import StrEnum MAJOR_VERSION: Final = 2021 MINOR_VERSION: Final = 12 -PATCH_VERSION: Final = "1" +PATCH_VERSION: Final = "2" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)