Compare commits

...

11 Commits

Author SHA1 Message Date
Franck Nijhof
7b462e1b8e 2022.12.0 (#83482) 2022-12-07 20:26:50 +01:00
puddly
92bc93466e Fix missing Shelly UnitOfTemperature import (#83483) 2022-12-07 18:45:16 +01:00
Franck Nijhof
54dd556459 Bumped version to 2022.12.0 2022-12-07 17:49:50 +01:00
Bram Kragten
8553faf3c8 Update frontend to 20221207.0 (#83479) 2022-12-07 17:49:22 +01:00
TheJulianJES
1631d10365 Cleanup ZHA initialization for TS011F child_lock (#83478) 2022-12-07 17:49:19 +01:00
Joakim Sørensen
141f37504d When an account exist without a subscription "provider" will not exist (#83472) 2022-12-07 17:49:16 +01:00
David F. Mulcahey
f97795fbb9 Bump the ZHA quirks lib to 0.0.88 (#83468) 2022-12-07 17:49:12 +01:00
Joakim Sørensen
ebf133ef80 Bump hass-nabucasa from 0.59.0 to 0.61.0 (#83466) 2022-12-07 17:49:08 +01:00
Franck Nijhof
886525112b Remove doubtful repairs issue from UniFi Protect (#83463) 2022-12-07 17:49:05 +01:00
Maciej Bieniek
9a15494e69 Fix restored temperature values in Shelly climate platform (#83428)
* Set last_target_temp value according the unit system

* Convert restored temperature values

* Add test

* Improve comments

* Move _last_target_temp value to constants
2022-12-07 17:49:01 +01:00
mbo18
047012d167 Add Child lock support to Tuya devices (#83233)
* Add Child lock support to Tuya devices

* flake/black

* Add attribute to general.py

* apply only to TS011F

* also update general.py
2022-12-07 17:48:56 +01:00
19 changed files with 112 additions and 102 deletions

View File

@@ -2,7 +2,7 @@
"domain": "cloud",
"name": "Home Assistant Cloud",
"documentation": "https://www.home-assistant.io/integrations/cloud",
"requirements": ["hass-nabucasa==0.59.0"],
"requirements": ["hass-nabucasa==0.61.0"],
"dependencies": ["http", "webhook"],
"after_dependencies": ["google_assistant", "alexa"],
"codeowners": ["@home-assistant/cloud"],

View File

@@ -30,7 +30,7 @@ def async_manage_legacy_subscription_issue(
If the provider is "legacy" create an issue,
in all other cases remove the issue.
"""
if subscription_info["provider"] == "legacy":
if subscription_info.get("provider") == "legacy":
ir.async_create_issue(
hass=hass,
domain=DOMAIN,

View File

@@ -2,7 +2,7 @@
"domain": "frontend",
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": ["home-assistant-frontend==20221206.0"],
"requirements": ["home-assistant-frontend==20221207.0"],
"dependencies": [
"api",
"auth",

View File

@@ -16,7 +16,7 @@ from homeassistant.components.climate import (
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry, entity_registry
@@ -24,6 +24,8 @@ from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.unit_conversion import TemperatureConverter
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import LOGGER, SHTRV_01_TEMPERATURE_SETTINGS
from .coordinator import ShellyBlockCoordinator, get_entry_data
@@ -108,7 +110,7 @@ class BlockSleepingClimate(
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
)
_attr_target_temperature_step = SHTRV_01_TEMPERATURE_SETTINGS["step"]
_attr_temperature_unit = TEMP_CELSIUS
_attr_temperature_unit = UnitOfTemperature.CELSIUS
def __init__(
self,
@@ -126,7 +128,14 @@ class BlockSleepingClimate(
self.last_state: State | None = None
self.last_state_attributes: Mapping[str, Any]
self._preset_modes: list[str] = []
self._last_target_temp = 20.0
if coordinator.hass.config.units is US_CUSTOMARY_SYSTEM:
self._last_target_temp = TemperatureConverter.convert(
SHTRV_01_TEMPERATURE_SETTINGS["default"],
UnitOfTemperature.CELSIUS,
UnitOfTemperature.FAHRENHEIT,
)
else:
self._last_target_temp = SHTRV_01_TEMPERATURE_SETTINGS["default"]
if self.block is not None and self.device_block is not None:
self._unique_id = f"{self.coordinator.mac}-{self.block.description}"
@@ -157,14 +166,32 @@ class BlockSleepingClimate(
"""Set target temperature."""
if self.block is not None:
return cast(float, self.block.targetTemp)
return self.last_state_attributes.get("temperature")
# The restored value can be in Fahrenheit so we have to convert it to Celsius
# because we use this unit internally in integration.
target_temp = self.last_state_attributes.get("temperature")
if self.hass.config.units is US_CUSTOMARY_SYSTEM and target_temp:
return TemperatureConverter.convert(
cast(float, target_temp),
UnitOfTemperature.FAHRENHEIT,
UnitOfTemperature.CELSIUS,
)
return target_temp
@property
def current_temperature(self) -> float | None:
"""Return current temperature."""
if self.block is not None:
return cast(float, self.block.temp)
return self.last_state_attributes.get("current_temperature")
# The restored value can be in Fahrenheit so we have to convert it to Celsius
# because we use this unit internally in integration.
current_temp = self.last_state_attributes.get("current_temperature")
if self.hass.config.units is US_CUSTOMARY_SYSTEM and current_temp:
return TemperatureConverter.convert(
cast(float, current_temp),
UnitOfTemperature.FAHRENHEIT,
UnitOfTemperature.CELSIUS,
)
return current_temp
@property
def available(self) -> bool:

View File

@@ -147,6 +147,7 @@ SHTRV_01_TEMPERATURE_SETTINGS: Final = {
"min": 4,
"max": 31,
"step": 0.5,
"default": 20.0,
}
# Kelvin value for colorTemp

View File

@@ -12,10 +12,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers.issue_registry import IssueSeverity
from .const import DOMAIN
from homeassistant.helpers import entity_registry as er
_LOGGER = logging.getLogger(__name__)
@@ -33,23 +30,6 @@ async def async_migrate_data(
await async_migrate_device_ids(hass, entry, protect)
_LOGGER.debug("Completed Migrate: async_migrate_device_ids")
entity_registry = er.async_get(hass)
for entity in er.async_entries_for_config_entry(entity_registry, entry.entry_id):
if (
entity.domain == Platform.SENSOR
and entity.disabled_by is None
and "detected_object" in entity.unique_id
):
ir.async_create_issue(
hass,
DOMAIN,
"deprecate_smart_sensor",
is_fixable=False,
breaks_in_ha_version="2023.2.0",
severity=IssueSeverity.WARNING,
translation_key="deprecate_smart_sensor",
)
async def async_get_bootstrap(protect: ProtectApiClient) -> Bootstrap:
"""Get UniFi Protect bootstrap or raise appropriate HA error."""

View File

@@ -75,10 +75,6 @@
"ea_setup_failed": {
"title": "Setup error using Early Access version",
"description": "You are using v{version} of UniFi Protect which is an Early Access version. An unrecoverable error occurred while trying to load the integration. Please [downgrade to a stable version](https://www.home-assistant.io/integrations/unifiprotect#downgrading-unifi-protect) of UniFi Protect to continue using the integration.\n\nError: {error}"
},
"deprecate_smart_sensor": {
"title": "Smart Detection Sensor Deprecated",
"description": "The unified \"Detected Object\" sensor for smart detections is now deprecated. It has been replaced with individual smart detection binary sensors for each smart detection type. Please update any templates or automations accordingly."
}
}
}

View File

@@ -42,10 +42,6 @@
}
},
"issues": {
"deprecate_smart_sensor": {
"description": "The unified \"Detected Object\" sensor for smart detections is now deprecated. It has been replaced with individual smart detection binary sensors for each smart detection type. Please update any templates or automations accordingly.",
"title": "Smart Detection Sensor Deprecated"
},
"ea_setup_failed": {
"description": "You are using v{version} of UniFi Protect which is an Early Access version. An unrecoverable error occurred while trying to load the integration. Please [downgrade to a stable version](https://www.home-assistant.io/integrations/unifiprotect#downgrading-unifi-protect) of UniFi Protect to continue using the integration.\n\nError: {error}",
"title": "Setup error using Early Access version"

View File

@@ -360,6 +360,8 @@ class OnOffChannel(ZigbeeChannel):
)
self.ZCL_INIT_ATTRS["backlight_mode"] = True
self.ZCL_INIT_ATTRS["power_on_state"] = True
if self.cluster.endpoint.model == "TS011F":
self.ZCL_INIT_ATTRS["child_lock"] = True
@property
def on_off(self) -> bool | None:

View File

@@ -7,7 +7,7 @@
"bellows==0.34.5",
"pyserial==3.5",
"pyserial-asyncio==0.6",
"zha-quirks==0.0.87",
"zha-quirks==0.0.88",
"zigpy-deconz==0.19.2",
"zigpy==0.52.3",
"zigpy-xbee==0.16.2",

View File

@@ -457,3 +457,15 @@ class AqaraPetFeederChildLock(ZHASwitchConfigurationEntity, id_suffix="child_loc
_zcl_attribute: str = "child_lock"
_attr_name = "Child lock"
_attr_icon: str = "mdi:account-lock"
@CONFIG_DIAGNOSTIC_MATCH(
channel_names=CHANNEL_ON_OFF,
models={"TS011F"},
)
class TuyaChildLockSwitch(ZHASwitchConfigurationEntity, id_suffix="child_lock"):
"""Representation of a child lock configuration entity."""
_zcl_attribute: str = "child_lock"
_attr_name = "Child lock"
_attr_icon: str = "mdi:account-lock"

View File

@@ -8,7 +8,7 @@ from .backports.enum import StrEnum
APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2022
MINOR_VERSION: Final = 12
PATCH_VERSION: Final = "0b7"
PATCH_VERSION: Final = "0"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)

View File

@@ -20,9 +20,9 @@ ciso8601==2.2.0
cryptography==38.0.3
dbus-fast==1.75.0
fnvhash==0.1.0
hass-nabucasa==0.59.0
hass-nabucasa==0.61.0
home-assistant-bluetooth==1.8.1
home-assistant-frontend==20221206.0
home-assistant-frontend==20221207.0
httpx==0.23.1
ifaddr==0.1.7
janus==1.0.0

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2022.12.0b7"
version = "2022.12.0"
license = {text = "Apache-2.0"}
description = "Open-source home automation platform running on Python 3."
readme = "README.rst"

View File

@@ -848,7 +848,7 @@ ha-philipsjs==2.9.0
habitipy==0.2.0
# homeassistant.components.cloud
hass-nabucasa==0.59.0
hass-nabucasa==0.61.0
# homeassistant.components.splunk
hass_splunk==0.1.1
@@ -884,7 +884,7 @@ hole==0.7.0
holidays==0.17.2
# homeassistant.components.frontend
home-assistant-frontend==20221206.0
home-assistant-frontend==20221207.0
# homeassistant.components.home_connect
homeconnect==0.7.2
@@ -2639,7 +2639,7 @@ zengge==0.2
zeroconf==0.39.4
# homeassistant.components.zha
zha-quirks==0.0.87
zha-quirks==0.0.88
# homeassistant.components.zhong_hong
zhong_hong_hvac==1.0.9

View File

@@ -640,7 +640,7 @@ ha-philipsjs==2.9.0
habitipy==0.2.0
# homeassistant.components.cloud
hass-nabucasa==0.59.0
hass-nabucasa==0.61.0
# homeassistant.components.tasmota
hatasmota==0.6.1
@@ -664,7 +664,7 @@ hole==0.7.0
holidays==0.17.2
# homeassistant.components.frontend
home-assistant-frontend==20221206.0
home-assistant-frontend==20221207.0
# homeassistant.components.home_connect
homeconnect==0.7.2
@@ -1840,7 +1840,7 @@ zamg==0.1.1
zeroconf==0.39.4
# homeassistant.components.zha
zha-quirks==0.0.87
zha-quirks==0.0.88
# homeassistant.components.zha
zigpy-deconz==0.19.2

View File

@@ -70,7 +70,7 @@ async def test_legacy_subscription_delete_issue_if_no_longer_legacy(
domain="cloud", issue_id="legacy_subscription"
)
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": None})
cloud_repairs.async_manage_legacy_subscription_issue(hass, {})
assert not issue_registry.async_get_issue(
domain="cloud", issue_id="legacy_subscription"
)

View File

@@ -21,6 +21,7 @@ from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
from homeassistant.core import State
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from . import init_integration, register_device, register_entity
@@ -212,6 +213,53 @@ async def test_block_restored_climate(hass, mock_block_device, device_reg, monke
assert hass.states.get(entity_id).state == HVACMode.OFF
async def test_block_restored_climate_us_customery(
hass, mock_block_device, device_reg, monkeypatch
):
"""Test block restored climate with US CUSTOMATY unit system."""
hass.config.units = US_CUSTOMARY_SYSTEM
monkeypatch.delattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "targetTemp")
monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "valveError", 0)
entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
register_device(device_reg, entry)
entity_id = register_entity(
hass,
CLIMATE_DOMAIN,
"test_name",
"sensor_0",
entry,
)
attrs = {"current_temperature": 67, "temperature": 68}
mock_restore_cache(hass, [State(entity_id, HVACMode.HEAT, attributes=attrs)])
monkeypatch.setattr(mock_block_device, "initialized", False)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == HVACMode.HEAT
assert hass.states.get(entity_id).attributes.get("temperature") == 68
assert hass.states.get(entity_id).attributes.get("current_temperature") == 67
# Partial update, should not change state
mock_block_device.mock_update()
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == HVACMode.HEAT
assert hass.states.get(entity_id).attributes.get("temperature") == 68
assert hass.states.get(entity_id).attributes.get("current_temperature") == 67
# Make device online
monkeypatch.setattr(mock_block_device, "initialized", True)
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 19.7)
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2)
mock_block_device.mock_update()
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == HVACMode.HEAT
assert hass.states.get(entity_id).attributes.get("temperature") == 67
assert hass.states.get(entity_id).attributes.get("current_temperature") == 65
async def test_block_restored_climate_unavailable(
hass, mock_block_device, device_reg, monkeypatch
):

View File

@@ -6,7 +6,7 @@ from copy import copy
from http import HTTPStatus
from unittest.mock import Mock
from pyunifiprotect.data import Camera, Version
from pyunifiprotect.data import Version
from homeassistant.components.repairs.issue_handler import (
async_process_repairs_platforms,
@@ -16,9 +16,7 @@ from homeassistant.components.repairs.websocket_api import (
RepairsFlowResourceView,
)
from homeassistant.components.unifiprotect.const import DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .utils import MockUFPFixture, init_entry
@@ -126,53 +124,3 @@ async def test_ea_warning_fix(
data = await resp.json()
assert data["type"] == "create_entry"
async def test_deprecate_smart_default(
hass: HomeAssistant, ufp: MockUFPFixture, hass_ws_client, doorbell: Camera
):
"""Test Deprecate Sensor repair does not exist by default (new installs)."""
await init_entry(hass, ufp, [doorbell])
await async_process_repairs_platforms(hass)
ws_client = await hass_ws_client(hass)
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
msg = await ws_client.receive_json()
assert msg["success"]
issue = None
for i in msg["result"]["issues"]:
if i["issue_id"] == "deprecate_smart_sensor":
issue = i
assert issue is None
async def test_deprecate_smart_active(
hass: HomeAssistant, ufp: MockUFPFixture, hass_ws_client, doorbell: Camera
):
"""Test Deprecate Sensor repair exists for existing installs."""
registry = er.async_get(hass)
registry.async_get_or_create(
Platform.SENSOR,
DOMAIN,
f"{doorbell.mac}_detected_object",
config_entry=ufp.entry,
)
await init_entry(hass, ufp, [doorbell])
await async_process_repairs_platforms(hass)
ws_client = await hass_ws_client(hass)
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
msg = await ws_client.receive_json()
assert msg["success"]
issue = None
for i in msg["result"]["issues"]:
if i["issue_id"] == "deprecate_smart_sensor":
issue = i
assert issue is not None