Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2021.12.10 #64317

Merged
merged 20 commits into from Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cb89c23
Avoid removing zwave_js devices for non-ready nodes (#59964)
kpine Dec 27, 2021
df2b6fd
Convert siri requests for target heating cooling state auto to a vali…
bdraco Jan 12, 2022
7320904
dlna_dmr: Allow for upnp attributes with None contents (#63892)
chishm Jan 11, 2022
2fb1e40
Convert disabled_by to DeviceEntryDisabler on load (#63944)
agners Jan 12, 2022
ba961b7
Fix homekit options being mutated during config_flow/migration (#64003)
bdraco Jan 12, 2022
7bcf3e8
Bump nexia to 0.9.13 to fix setting emergency heat (#64020)
bdraco Jan 13, 2022
7a886ef
Bump flux_led to 0.28.3 to fix setting colorloop on older models (#64…
bdraco Jan 13, 2022
405c4f6
Fix changing the preset mode (#64119)
bieniu Jan 14, 2022
4f09439
Fix flux_led turn on when brightness is zero on newer devices (#64129)
bdraco Jan 14, 2022
9f281e0
Ensure august status is current when integration loads (#64027)
bdraco Jan 13, 2022
8f842c7
Fix august lock/unlock with older bridges (#64143)
bdraco Jan 14, 2022
da5b473
Ignore unavailable entities when creating zwave_js device actions lis…
raman325 Jan 16, 2022
ec993b1
Fix KNX onboarding when there is no yaml config defined yet (#64216)
farmio Jan 17, 2022
8c531b4
Bump bimmer_connected to 0.8.10 (#64314)
rikroe Jan 17, 2022
1c82a56
Bumped version to 2021.12.10
balloob Jan 17, 2022
69c5b04
lint
balloob Jan 17, 2022
777c5b7
Ensure status is correct at start for older august bridges (#64144)
bdraco Jan 15, 2022
bfe657a
Bump flux_led to 0.28.4 to fix setting white temp on 0x35 devices (#6…
bdraco Jan 17, 2022
959498d
Orphaned MAC addresses breaks UniFi options flow (#64327)
Kane610 Jan 17, 2022
c312654
remove typing
balloob Jan 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 25 additions & 2 deletions homeassistant/components/august/__init__.py
Expand Up @@ -138,6 +138,17 @@ async def async_setup(self):
pubnub.subscribe(self.async_pubnub_message)
self._pubnub_unsub = async_create_pubnub(user_data["UserID"], pubnub)

if self._locks_by_id:
tasks = []
for lock_id in self._locks_by_id:
detail = self._device_detail_by_id[lock_id]
tasks.append(
self.async_status_async(
lock_id, bool(detail.bridge and detail.bridge.hyper_bridge)
)
)
await asyncio.gather(*tasks)

@callback
def async_pubnub_message(self, device_id, date_time, message):
"""Process a pubnub message."""
Expand Down Expand Up @@ -245,13 +256,24 @@ async def async_lock(self, device_id):
device_id,
)

async def async_lock_async(self, device_id):
async def async_status_async(self, device_id, hyper_bridge):
"""Request status of the the device but do not wait for a response since it will come via pubnub."""
return await self._async_call_api_op_requires_bridge(
device_id,
self._api.async_status_async,
self._august_gateway.access_token,
device_id,
hyper_bridge,
)

async def async_lock_async(self, device_id, hyper_bridge):
"""Lock the device but do not wait for a response since it will come via pubnub."""
return await self._async_call_api_op_requires_bridge(
device_id,
self._api.async_lock_async,
self._august_gateway.access_token,
device_id,
hyper_bridge,
)

async def async_unlock(self, device_id):
Expand All @@ -263,13 +285,14 @@ async def async_unlock(self, device_id):
device_id,
)

async def async_unlock_async(self, device_id):
async def async_unlock_async(self, device_id, hyper_bridge):
"""Unlock the device but do not wait for a response since it will come via pubnub."""
return await self._async_call_api_op_requires_bridge(
device_id,
self._api.async_unlock_async,
self._august_gateway.access_token,
device_id,
hyper_bridge,
)

async def _async_call_api_op_requires_bridge(
Expand Down
9 changes: 7 additions & 2 deletions homeassistant/components/august/lock.py
Expand Up @@ -39,17 +39,22 @@ def __init__(self, data, device):
self._attr_unique_id = f"{self._device_id:s}_lock"
self._update_from_data()

@property
def _hyper_bridge(self):
"""Check if the lock has a paired hyper bridge."""
return bool(self._detail.bridge and self._detail.bridge.hyper_bridge)

async def async_lock(self, **kwargs):
"""Lock the device."""
if self._data.activity_stream.pubnub.connected:
await self._data.async_lock_async(self._device_id)
await self._data.async_lock_async(self._device_id, self._hyper_bridge)
return
await self._call_lock_operation(self._data.async_lock)

async def async_unlock(self, **kwargs):
"""Unlock the device."""
if self._data.activity_stream.pubnub.connected:
await self._data.async_unlock_async(self._device_id)
await self._data.async_unlock_async(self._device_id, self._hyper_bridge)
return
await self._call_lock_operation(self._data.async_unlock)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/august/manifest.json
Expand Up @@ -2,7 +2,7 @@
"domain": "august",
"name": "August",
"documentation": "https://www.home-assistant.io/integrations/august",
"requirements": ["yalexs==1.1.17"],
"requirements": ["yalexs==1.1.19"],
"codeowners": ["@bdraco"],
"dhcp": [
{
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bmw_connected_drive/manifest.json
Expand Up @@ -2,7 +2,7 @@
"domain": "bmw_connected_drive",
"name": "BMW Connected Drive",
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
"requirements": ["bimmer_connected==0.8.7"],
"requirements": ["bimmer_connected==0.8.10"],
"codeowners": ["@gerard33", "@rikroe"],
"config_flow": true,
"iot_class": "cloud_polling"
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/dlna_dmr/config_flow.py
Expand Up @@ -474,8 +474,8 @@ def _is_ignored_device(discovery_info: ssdp.SsdpServiceInfo) -> bool:
# Special cases for devices with other discovery methods (e.g. mDNS), or
# that advertise multiple unrelated (sent in separate discovery packets)
# UPnP devices.
manufacturer = discovery_info.upnp.get(ssdp.ATTR_UPNP_MANUFACTURER, "").lower()
model = discovery_info.upnp.get(ssdp.ATTR_UPNP_MODEL_NAME, "").lower()
manufacturer = (discovery_info.upnp.get(ssdp.ATTR_UPNP_MANUFACTURER) or "").lower()
model = (discovery_info.upnp.get(ssdp.ATTR_UPNP_MODEL_NAME) or "").lower()

if manufacturer.startswith("xbmc") or model == "kodi":
# kodi
Expand Down
42 changes: 28 additions & 14 deletions homeassistant/components/flux_led/light.py
Expand Up @@ -71,7 +71,14 @@
TRANSITION_STROBE,
)
from .entity import FluxOnOffEntity
from .util import _effect_brightness, _flux_color_mode_to_hass, _hass_color_modes
from .util import (
_effect_brightness,
_flux_color_mode_to_hass,
_hass_color_modes,
_min_rgb_brightness,
_min_rgbw_brightness,
_min_rgbwc_brightness,
)

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -244,7 +251,7 @@ def __init__(
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return self._device.brightness
return self._device.brightness # type: ignore

@property
def color_temp(self) -> int:
Expand All @@ -254,17 +261,17 @@ def color_temp(self) -> int:
@property
def rgb_color(self) -> tuple[int, int, int]:
"""Return the rgb color value."""
return self._device.rgb_unscaled
return self._device.rgb_unscaled # type: ignore

@property
def rgbw_color(self) -> tuple[int, int, int, int]:
"""Return the rgbw color value."""
return self._device.rgbw
return self._device.rgbw # type: ignore

@property
def rgbww_color(self) -> tuple[int, int, int, int, int]:
"""Return the rgbww aka rgbcw color value."""
return self._device.rgbcw
return self._device.rgbcw # type: ignore

@property
def color_mode(self) -> str:
Expand All @@ -276,7 +283,7 @@ def color_mode(self) -> str:
@property
def effect(self) -> str | None:
"""Return the current effect."""
return self._device.effect
return self._device.effect # type: ignore

async def _async_turn_on(self, **kwargs: Any) -> None:
"""Turn the specified or all lights on."""
Expand Down Expand Up @@ -313,13 +320,13 @@ def _async_brightness(self, **kwargs: Any) -> int:
"""Determine brightness from kwargs or current value."""
if (brightness := kwargs.get(ATTR_BRIGHTNESS)) is None:
brightness = self.brightness
if not brightness:
# If the brightness was previously 0, the light
# will not turn on unless brightness is at least 1
# If the device was on and brightness was not
# set, it means it was masked by an effect
brightness = 255 if self.is_on else 1
return brightness
# If the brightness was previously 0, the light
# will not turn on unless brightness is at least 1
#
# We previously had a problem with the brightness
# sometimes reporting as 0 when an effect was in progress,
# however this has since been resolved in the upstream library
return max(1, brightness)

async def _async_set_mode(self, **kwargs: Any) -> None:
"""Set an effect or color mode."""
Expand Down Expand Up @@ -348,20 +355,27 @@ async def _async_set_mode(self, **kwargs: Any) -> None:
return
# Handle switch to RGB Color Mode
if rgb := kwargs.get(ATTR_RGB_COLOR):
if not self._device.requires_turn_on:
rgb = _min_rgb_brightness(rgb)
red, green, blue = rgb
await self._device.async_set_levels(red, green, blue, brightness=brightness)
return
# Handle switch to RGBW Color Mode
if rgbw := kwargs.get(ATTR_RGBW_COLOR):
if ATTR_BRIGHTNESS in kwargs:
rgbw = rgbw_brightness(rgbw, brightness)
if not self._device.requires_turn_on:
rgbw = _min_rgbw_brightness(rgbw)
await self._device.async_set_levels(*rgbw)
return
# Handle switch to RGBWW Color Mode
if rgbcw := kwargs.get(ATTR_RGBWW_COLOR):
if ATTR_BRIGHTNESS in kwargs:
rgbcw = rgbcw_brightness(kwargs[ATTR_RGBWW_COLOR], brightness)
await self._device.async_set_levels(*rgbcw_to_rgbwc(rgbcw))
rgbwc = rgbcw_to_rgbwc(rgbcw)
if not self._device.requires_turn_on:
rgbwc = _min_rgbwc_brightness(rgbwc)
await self._device.async_set_levels(*rgbwc)
return
if (white := kwargs.get(ATTR_WHITE)) is not None:
await self._device.async_set_levels(w=white)
Expand Down
65 changes: 32 additions & 33 deletions homeassistant/components/flux_led/manifest.json
Expand Up @@ -3,42 +3,41 @@
"name": "Flux LED/MagicHome",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/flux_led",
"requirements": ["flux_led==0.27.45"],
"requirements": ["flux_led==0.28.4"],
"quality_scale": "platinum",
"codeowners": ["@icemanch"],
"iot_class": "local_push",
"dhcp": [
{
"macaddress": "18B905*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "249494*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "7CB94C*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "B4E842*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "F0FE6B*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "8CCE4E*",
"hostname": "lwip*"
},
{
"hostname": "zengge_[0-9a-f][0-9a-f]_*"
},
{
"macaddress": "C82E47*",
"hostname": "sta*"
}
{
"macaddress": "18B905*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "249494*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "7CB94C*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "B4E842*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "F0FE6B*",
"hostname": "[ba][lk]*"
},
{
"macaddress": "8CCE4E*",
"hostname": "lwip*"
},
{
"hostname": "zengge_[0-9a-f][0-9a-f]_*"
},
{
"macaddress": "C82E47*",
"hostname": "sta*"
}
]
}

23 changes: 23 additions & 0 deletions homeassistant/components/flux_led/util.py
Expand Up @@ -34,3 +34,26 @@ def _flux_color_mode_to_hass(
def _effect_brightness(brightness: int) -> int:
"""Convert hass brightness to effect brightness."""
return round(brightness / 255 * 100)


def _min_rgb_brightness(rgb: tuple[int, int, int]) -> tuple[int, int, int]:
"""Ensure the RGB value will not turn off the device from a turn on command."""
if all(byte == 0 for byte in rgb):
return (1, 1, 1)
return rgb


def _min_rgbw_brightness(rgbw: tuple[int, int, int, int]) -> tuple[int, int, int, int]:
"""Ensure the RGBW value will not turn off the device from a turn on command."""
if all(byte == 0 for byte in rgbw):
return (1, 1, 1, 0)
return rgbw


def _min_rgbwc_brightness(
rgbwc: tuple[int, int, int, int, int]
) -> tuple[int, int, int, int, int]:
"""Ensure the RGBWC value will not turn off the device from a turn on command."""
if all(byte == 0 for byte in rgbwc):
return (1, 1, 1, 0, 0)
return rgbwc
5 changes: 3 additions & 2 deletions homeassistant/components/homekit/__init__.py
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

import asyncio
from copy import deepcopy
import ipaddress
import logging
import os
Expand Down Expand Up @@ -352,8 +353,8 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry):

@callback
def _async_import_options_from_data_if_missing(hass: HomeAssistant, entry: ConfigEntry):
options = dict(entry.options)
data = dict(entry.data)
options = deepcopy(dict(entry.options))
data = deepcopy(dict(entry.data))
modified = False
for importable_option in CONFIG_OPTIONS:
if importable_option not in entry.options and importable_option in entry.data:
Expand Down
8 changes: 5 additions & 3 deletions homeassistant/components/homekit/config_flow.py
Expand Up @@ -2,9 +2,11 @@
from __future__ import annotations

import asyncio
from copy import deepcopy
import random
import re
import string
from typing import Final

import voluptuous as vol

Expand Down Expand Up @@ -116,7 +118,7 @@
"water_heater",
]

_EMPTY_ENTITY_FILTER = {
_EMPTY_ENTITY_FILTER: Final = {
CONF_INCLUDE_DOMAINS: [],
CONF_EXCLUDE_DOMAINS: [],
CONF_INCLUDE_ENTITIES: [],
Expand Down Expand Up @@ -151,7 +153,7 @@ def __init__(self) -> None:
async def async_step_user(self, user_input=None):
"""Choose specific domains in bridge mode."""
if user_input is not None:
entity_filter = _EMPTY_ENTITY_FILTER.copy()
entity_filter = deepcopy(_EMPTY_ENTITY_FILTER)
entity_filter[CONF_INCLUDE_DOMAINS] = user_input[CONF_INCLUDE_DOMAINS]
self.hk_data[CONF_FILTER] = entity_filter
return await self.async_step_pairing()
Expand Down Expand Up @@ -492,7 +494,7 @@ async def async_step_init(self, user_input=None):
self.hk_options.update(user_input)
return await self.async_step_include_exclude()

self.hk_options = dict(self.config_entry.options)
self.hk_options = deepcopy(dict(self.config_entry.options))
entity_filter = self.hk_options.get(CONF_FILTER, {})
homekit_mode = self.hk_options.get(CONF_HOMEKIT_MODE, DEFAULT_HOMEKIT_MODE)
domains = entity_filter.get(CONF_INCLUDE_DOMAINS, [])
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/homekit/manifest.json
Expand Up @@ -3,7 +3,7 @@
"name": "HomeKit",
"documentation": "https://www.home-assistant.io/integrations/homekit",
"requirements": [
"HAP-python==4.3.0",
"HAP-python==4.4.0",
"fnvhash==0.1.0",
"PyQRCode==1.2.1",
"base36==0.1.1"
Expand Down