mirror of
https://github.com/home-assistant/core.git
synced 2026-03-02 13:56:56 +01:00
Compare commits
10 Commits
config-yam
...
ubisys_vir
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ae3e101d5 | ||
|
|
0aa66ed6cb | ||
|
|
6903463f14 | ||
|
|
a473010fee | ||
|
|
ddf7a783a8 | ||
|
|
513e4d52fe | ||
|
|
17bb14e260 | ||
|
|
cd1258464b | ||
|
|
d3f5e0e6d7 | ||
|
|
9823e31206 |
5
homeassistant/brands/ubisys.json
Normal file
5
homeassistant/brands/ubisys.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"domain": "ubisys",
|
||||
"name": "Ubisys",
|
||||
"iot_standards": ["zigbee"]
|
||||
}
|
||||
@@ -191,7 +191,7 @@ class AccuWeatherEntity(
|
||||
{
|
||||
ATTR_FORECAST_TIME: utc_from_timestamp(item["EpochDate"]).isoformat(),
|
||||
ATTR_FORECAST_CLOUD_COVERAGE: item["CloudCoverDay"],
|
||||
ATTR_FORECAST_HUMIDITY: item["RelativeHumidityDay"]["Average"],
|
||||
ATTR_FORECAST_HUMIDITY: item["RelativeHumidityDay"].get("Average"),
|
||||
ATTR_FORECAST_NATIVE_TEMP: item["TemperatureMax"][ATTR_VALUE],
|
||||
ATTR_FORECAST_NATIVE_TEMP_LOW: item["TemperatureMin"][ATTR_VALUE],
|
||||
ATTR_FORECAST_NATIVE_APPARENT_TEMP: item["RealFeelTemperatureMax"][
|
||||
|
||||
@@ -7,7 +7,7 @@ import asyncio
|
||||
from http import HTTPStatus
|
||||
import logging
|
||||
|
||||
from aiohttp import ClientError, ClientResponseError, web
|
||||
from aiohttp import ClientError, web
|
||||
from google_nest_sdm.camera_traits import CameraClipPreviewTrait
|
||||
from google_nest_sdm.device import Device
|
||||
from google_nest_sdm.device_manager import DeviceManager
|
||||
@@ -43,6 +43,8 @@ from homeassistant.exceptions import (
|
||||
ConfigEntryAuthFailed,
|
||||
ConfigEntryNotReady,
|
||||
HomeAssistantError,
|
||||
OAuth2TokenRequestError,
|
||||
OAuth2TokenRequestReauthError,
|
||||
Unauthorized,
|
||||
)
|
||||
from homeassistant.helpers import (
|
||||
@@ -253,11 +255,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: NestConfigEntry) -> bool
|
||||
auth = await api.new_auth(hass, entry)
|
||||
try:
|
||||
await auth.async_get_access_token()
|
||||
except ClientResponseError as err:
|
||||
if 400 <= err.status < 500:
|
||||
raise ConfigEntryAuthFailed(
|
||||
translation_domain=DOMAIN, translation_key="reauth_required"
|
||||
) from err
|
||||
except OAuth2TokenRequestReauthError as err:
|
||||
raise ConfigEntryAuthFailed(
|
||||
translation_domain=DOMAIN, translation_key="reauth_required"
|
||||
) from err
|
||||
except OAuth2TokenRequestError as err:
|
||||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN, translation_key="auth_server_error"
|
||||
) from err
|
||||
|
||||
@@ -49,12 +49,12 @@ class PowerfoxLocalDataUpdateCoordinator(DataUpdateCoordinator[LocalResponse]):
|
||||
except PowerfoxAuthenticationError as err:
|
||||
raise ConfigEntryAuthFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="invalid_auth",
|
||||
translation_placeholders={"error": str(err)},
|
||||
translation_key="auth_failed",
|
||||
translation_placeholders={"host": self.config_entry.data[CONF_HOST]},
|
||||
) from err
|
||||
except PowerfoxConnectionError as err:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="update_failed",
|
||||
translation_placeholders={"error": str(err)},
|
||||
translation_key="connection_error",
|
||||
translation_placeholders={"host": self.config_entry.data[CONF_HOST]},
|
||||
) from err
|
||||
|
||||
@@ -56,11 +56,11 @@
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"invalid_auth": {
|
||||
"message": "Error while authenticating with the device: {error}"
|
||||
"auth_failed": {
|
||||
"message": "Authentication with the Poweropti device at {host} failed. Please check your API key."
|
||||
},
|
||||
"update_failed": {
|
||||
"message": "Error while updating the device: {error}"
|
||||
"connection_error": {
|
||||
"message": "Could not connect to the Poweropti device at {host}. Please check if the device is online and reachable."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pysmarlaapi", "pysignalr"],
|
||||
"quality_scale": "bronze",
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["pysmarlaapi==1.0.1"]
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class SmartThingsButtonDescription(ButtonEntityDescription):
|
||||
|
||||
key: Capability
|
||||
command: Command
|
||||
component: str = MAIN
|
||||
|
||||
|
||||
CAPABILITIES_TO_BUTTONS: dict[Capability | str, SmartThingsButtonDescription] = {
|
||||
@@ -42,6 +43,13 @@ CAPABILITIES_TO_BUTTONS: dict[Capability | str, SmartThingsButtonDescription] =
|
||||
command=Command.RESET_HOOD_FILTER,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
Capability.CUSTOM_HEPA_FILTER: SmartThingsButtonDescription(
|
||||
key=Capability.CUSTOM_HEPA_FILTER,
|
||||
translation_key="reset_hepa_filter",
|
||||
command=Command.RESET_HEPA_FILTER,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
component="station",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +61,11 @@ async def async_setup_entry(
|
||||
"""Add button entities for a config entry."""
|
||||
entry_data = entry.runtime_data
|
||||
async_add_entities(
|
||||
SmartThingsButtonEntity(
|
||||
entry_data.client, device, CAPABILITIES_TO_BUTTONS[capability]
|
||||
)
|
||||
SmartThingsButtonEntity(entry_data.client, device, description)
|
||||
for capability, description in CAPABILITIES_TO_BUTTONS.items()
|
||||
for device in entry_data.devices.values()
|
||||
for capability in device.status[MAIN]
|
||||
if capability in CAPABILITIES_TO_BUTTONS
|
||||
if description.component in device.status
|
||||
and capability in device.status[description.component]
|
||||
)
|
||||
|
||||
|
||||
@@ -74,9 +81,9 @@ class SmartThingsButtonEntity(SmartThingsEntity, ButtonEntity):
|
||||
entity_description: SmartThingsButtonDescription,
|
||||
) -> None:
|
||||
"""Initialize the instance."""
|
||||
super().__init__(client, device, set())
|
||||
super().__init__(client, device, set(), component=entity_description.component)
|
||||
self.entity_description = entity_description
|
||||
self._attr_unique_id = f"{device.device.device_id}_{MAIN}_{entity_description.key}_{entity_description.command}"
|
||||
self._attr_unique_id = f"{device.device.device_id}_{entity_description.component}_{entity_description.key}_{entity_description.command}"
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"reset_hepa_filter": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"reset_water_filter": {
|
||||
"default": "mdi:reload"
|
||||
},
|
||||
@@ -93,6 +96,9 @@
|
||||
"stop": "mdi:stop"
|
||||
}
|
||||
},
|
||||
"robot_cleaner_driving_mode": {
|
||||
"default": "mdi:car-cog"
|
||||
},
|
||||
"selected_zone": {
|
||||
"state": {
|
||||
"all": "mdi:card",
|
||||
|
||||
@@ -26,6 +26,12 @@ LAMP_TO_HA = {
|
||||
"off": "off",
|
||||
}
|
||||
|
||||
DRIVING_MODE_TO_HA = {
|
||||
"areaThenWalls": "area_then_walls",
|
||||
"wallFirst": "walls_first",
|
||||
"quickCleaningZigzagPattern": "quick_clean_zigzag_pattern",
|
||||
}
|
||||
|
||||
WASHER_SOIL_LEVEL_TO_HA = {
|
||||
"none": "none",
|
||||
"heavy": "heavy",
|
||||
@@ -187,6 +193,15 @@ CAPABILITIES_TO_SELECT: dict[Capability | str, SmartThingsSelectDescription] = {
|
||||
options_map=WASHER_WATER_TEMPERATURE_TO_HA,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
Capability.SAMSUNG_CE_ROBOT_CLEANER_DRIVING_MODE: SmartThingsSelectDescription(
|
||||
key=Capability.SAMSUNG_CE_ROBOT_CLEANER_DRIVING_MODE,
|
||||
translation_key="robot_cleaner_driving_mode",
|
||||
options_attribute=Attribute.SUPPORTED_DRIVING_MODES,
|
||||
status_attribute=Attribute.DRIVING_MODE,
|
||||
command=Command.SET_DRIVING_MODE,
|
||||
options_map=DRIVING_MODE_TO_HA,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
Capability.SAMSUNG_CE_DUST_FILTER_ALARM: SmartThingsSelectDescription(
|
||||
key=Capability.SAMSUNG_CE_DUST_FILTER_ALARM,
|
||||
translation_key="dust_filter_alarm",
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"reset_hepa_filter": {
|
||||
"name": "Reset HEPA filter"
|
||||
},
|
||||
"reset_hood_filter": {
|
||||
"name": "Reset filter"
|
||||
},
|
||||
@@ -223,6 +226,14 @@
|
||||
"stop": "[%key:common::state::stopped%]"
|
||||
}
|
||||
},
|
||||
"robot_cleaner_driving_mode": {
|
||||
"name": "Driving mode",
|
||||
"state": {
|
||||
"area_then_walls": "Area then walls",
|
||||
"quick_clean_zigzag_pattern": "Quick clean in a zigzag pattern",
|
||||
"walls_first": "Walls first"
|
||||
}
|
||||
},
|
||||
"selected_zone": {
|
||||
"name": "Selected zone",
|
||||
"state": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
from typing import Any, Final
|
||||
from typing import Any, Final, cast
|
||||
|
||||
from aiohttp import ClientError, ClientResponseError
|
||||
from tesla_fleet_api.const import Scope
|
||||
@@ -106,7 +106,7 @@ async def _get_access_token(oauth_session: OAuth2Session) -> str:
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="not_ready_connection_error",
|
||||
) from err
|
||||
return str(oauth_session.token[CONF_ACCESS_TOKEN])
|
||||
return cast(str, oauth_session.token[CONF_ACCESS_TOKEN])
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) -> bool:
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["tessie", "tesla-fleet-api"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["tessie-api==0.1.1", "tesla-fleet-api==1.4.3"]
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ rules:
|
||||
comment: |
|
||||
No custom actions are defined. Only entity-based actions exist.
|
||||
config-entry-unloading: done
|
||||
docs-configuration-parameters: todo
|
||||
docs-configuration-parameters:
|
||||
status: exempt
|
||||
comment: |
|
||||
No options flow and no configurable options after initial setup.
|
||||
docs-installation-parameters: done
|
||||
entity-unavailable: done
|
||||
integration-owner: done
|
||||
|
||||
@@ -7338,6 +7338,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ubisys": {
|
||||
"name": "Ubisys",
|
||||
"iot_standards": [
|
||||
"zigbee"
|
||||
]
|
||||
},
|
||||
"ubiwizz": {
|
||||
"name": "Ubiwizz",
|
||||
"integration_type": "virtual",
|
||||
|
||||
@@ -1945,7 +1945,6 @@ INTEGRATIONS_WITHOUT_SCALE = [
|
||||
"template",
|
||||
"tesla_fleet",
|
||||
"tesla_wall_connector",
|
||||
"tessie",
|
||||
"tfiac",
|
||||
"thermobeacon",
|
||||
"thermopro",
|
||||
|
||||
@@ -136,6 +136,31 @@ async def test_forecast_service(
|
||||
assert response == snapshot
|
||||
|
||||
|
||||
async def test_forecast_daily_missing_average_humidity(
|
||||
hass: HomeAssistant,
|
||||
mock_accuweather_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test daily forecast does not crash when average humidity is missing."""
|
||||
mock_accuweather_client.async_get_daily_forecast.return_value[0][
|
||||
"RelativeHumidityDay"
|
||||
] = {}
|
||||
|
||||
await init_integration(hass)
|
||||
|
||||
response = await hass.services.async_call(
|
||||
WEATHER_DOMAIN,
|
||||
SERVICE_GET_FORECASTS,
|
||||
{
|
||||
"entity_id": "weather.home",
|
||||
"type": "daily",
|
||||
},
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
assert response["weather.home"]["forecast"][0].get("humidity") is None
|
||||
|
||||
|
||||
async def test_forecast_subscription(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
|
||||
@@ -440,3 +440,52 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_rvc_map_01011][button.robot_vacuum_reset_hepa_filter-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'button.robot_vacuum_reset_hepa_filter',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Reset HEPA filter',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Reset HEPA filter',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'reset_hepa_filter',
|
||||
'unique_id': '01b28624-5907-c8bc-0325-8ad23f03a637_station_custom.hepaFilter_resetHepaFilter',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_rvc_map_01011][button.robot_vacuum_reset_hepa_filter-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Robot Vacuum Reset HEPA filter',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.robot_vacuum_reset_hepa_filter',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -415,6 +415,66 @@
|
||||
'state': 'high',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_rvc_map_01011][select.robot_vacuum_driving_mode-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'area_then_walls',
|
||||
'walls_first',
|
||||
'quick_clean_zigzag_pattern',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.robot_vacuum_driving_mode',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Driving mode',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Driving mode',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'robot_cleaner_driving_mode',
|
||||
'unique_id': '01b28624-5907-c8bc-0325-8ad23f03a637_main_samsungce.robotCleanerDrivingMode_drivingMode_drivingMode',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_rvc_map_01011][select.robot_vacuum_driving_mode-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Robot Vacuum Driving mode',
|
||||
'options': list([
|
||||
'area_then_walls',
|
||||
'walls_first',
|
||||
'quick_clean_zigzag_pattern',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.robot_vacuum_driving_mode',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'area_then_walls',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_rvc_map_01011][select.robot_vacuum_lamp-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
Reference in New Issue
Block a user