mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Merge pull request #66624 from home-assistant/rc
This commit is contained in:
commit
e33671db60
@ -7,7 +7,7 @@
|
|||||||
"@Bre77"
|
"@Bre77"
|
||||||
],
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"advantage_air==0.2.5"
|
"advantage_air==0.3.0"
|
||||||
],
|
],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"iot_class": "local_polling"
|
"iot_class": "local_polling"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["network"],
|
"dependencies": ["network"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/flux_led",
|
"documentation": "https://www.home-assistant.io/integrations/flux_led",
|
||||||
"requirements": ["flux_led==0.28.22"],
|
"requirements": ["flux_led==0.28.26"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"codeowners": ["@icemanch", "@bdraco"],
|
"codeowners": ["@icemanch", "@bdraco"],
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
|
@ -12,10 +12,9 @@ from homeassistant.components.button import (
|
|||||||
ButtonEntityDescription,
|
ButtonEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .common import AvmWrapper
|
from .common import AvmWrapper
|
||||||
@ -41,28 +40,28 @@ BUTTONS: Final = [
|
|||||||
key="firmware_update",
|
key="firmware_update",
|
||||||
name="Firmware Update",
|
name="Firmware Update",
|
||||||
device_class=ButtonDeviceClass.UPDATE,
|
device_class=ButtonDeviceClass.UPDATE,
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_firmware_update(),
|
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_firmware_update(),
|
||||||
),
|
),
|
||||||
FritzButtonDescription(
|
FritzButtonDescription(
|
||||||
key="reboot",
|
key="reboot",
|
||||||
name="Reboot",
|
name="Reboot",
|
||||||
device_class=ButtonDeviceClass.RESTART,
|
device_class=ButtonDeviceClass.RESTART,
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reboot(),
|
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reboot(),
|
||||||
),
|
),
|
||||||
FritzButtonDescription(
|
FritzButtonDescription(
|
||||||
key="reconnect",
|
key="reconnect",
|
||||||
name="Reconnect",
|
name="Reconnect",
|
||||||
device_class=ButtonDeviceClass.RESTART,
|
device_class=ButtonDeviceClass.RESTART,
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reconnect(),
|
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reconnect(),
|
||||||
),
|
),
|
||||||
FritzButtonDescription(
|
FritzButtonDescription(
|
||||||
key="cleanup",
|
key="cleanup",
|
||||||
name="Cleanup",
|
name="Cleanup",
|
||||||
icon="mdi:broom",
|
icon="mdi:broom",
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_cleanup(),
|
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_cleanup(),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -327,10 +327,18 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator):
|
|||||||
_LOGGER.debug("Checking host info for FRITZ!Box device %s", self.host)
|
_LOGGER.debug("Checking host info for FRITZ!Box device %s", self.host)
|
||||||
self._update_available, self._latest_firmware = self._update_device_info()
|
self._update_available, self._latest_firmware = self._update_device_info()
|
||||||
|
|
||||||
|
if (
|
||||||
|
"Hosts1" not in self.connection.services
|
||||||
|
or "X_AVM-DE_GetMeshListPath"
|
||||||
|
not in self.connection.services["Hosts1"].actions
|
||||||
|
):
|
||||||
|
self.mesh_role = MeshRoles.NONE
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
topology = self.fritz_hosts.get_mesh_topology()
|
topology = self.fritz_hosts.get_mesh_topology()
|
||||||
except FritzActionError:
|
except FritzActionError:
|
||||||
self.mesh_role = MeshRoles.SLAVE
|
self.mesh_role = MeshRoles.SLAVE
|
||||||
|
# Avoid duplicating device trackers
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug("Checking devices for FRITZ!Box device %s", self.host)
|
_LOGGER.debug("Checking devices for FRITZ!Box device %s", self.host)
|
||||||
|
@ -13,8 +13,8 @@ from homeassistant.components.binary_sensor import (
|
|||||||
BinarySensorEntityDescription,
|
BinarySensorEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import FritzBoxEntity
|
from . import FritzBoxEntity
|
||||||
@ -49,7 +49,7 @@ BINARY_SENSOR_TYPES: Final[tuple[FritzBinarySensorEntityDescription, ...]] = (
|
|||||||
key="lock",
|
key="lock",
|
||||||
name="Button Lock on Device",
|
name="Button Lock on Device",
|
||||||
device_class=BinarySensorDeviceClass.LOCK,
|
device_class=BinarySensorDeviceClass.LOCK,
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
suitable=lambda device: device.lock is not None,
|
suitable=lambda device: device.lock is not None,
|
||||||
is_on=lambda device: not device.lock,
|
is_on=lambda device: not device.lock,
|
||||||
),
|
),
|
||||||
@ -57,7 +57,7 @@ BINARY_SENSOR_TYPES: Final[tuple[FritzBinarySensorEntityDescription, ...]] = (
|
|||||||
key="device_lock",
|
key="device_lock",
|
||||||
name="Button Lock via UI",
|
name="Button Lock via UI",
|
||||||
device_class=BinarySensorDeviceClass.LOCK,
|
device_class=BinarySensorDeviceClass.LOCK,
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
suitable=lambda device: device.device_lock is not None,
|
suitable=lambda device: device.device_lock is not None,
|
||||||
is_on=lambda device: not device.device_lock,
|
is_on=lambda device: not device.device_lock,
|
||||||
),
|
),
|
||||||
|
@ -9,9 +9,9 @@ from goodwe import Inverter, InverterError
|
|||||||
|
|
||||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG, PERCENTAGE, POWER_WATT
|
from homeassistant.const import PERCENTAGE, POWER_WATT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN, KEY_DEVICE_INFO, KEY_INVERTER
|
from .const import DOMAIN, KEY_DEVICE_INFO, KEY_INVERTER
|
||||||
@ -39,7 +39,7 @@ NUMBERS = (
|
|||||||
key="grid_export_limit",
|
key="grid_export_limit",
|
||||||
name="Grid export limit",
|
name="Grid export limit",
|
||||||
icon="mdi:transmission-tower",
|
icon="mdi:transmission-tower",
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
unit_of_measurement=POWER_WATT,
|
unit_of_measurement=POWER_WATT,
|
||||||
getter=lambda inv: inv.get_grid_export_limit(),
|
getter=lambda inv: inv.get_grid_export_limit(),
|
||||||
setter=lambda inv, val: inv.set_grid_export_limit(val),
|
setter=lambda inv, val: inv.set_grid_export_limit(val),
|
||||||
@ -51,7 +51,7 @@ NUMBERS = (
|
|||||||
key="battery_discharge_depth",
|
key="battery_discharge_depth",
|
||||||
name="Depth of discharge (on-grid)",
|
name="Depth of discharge (on-grid)",
|
||||||
icon="mdi:battery-arrow-down",
|
icon="mdi:battery-arrow-down",
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
unit_of_measurement=PERCENTAGE,
|
unit_of_measurement=PERCENTAGE,
|
||||||
getter=lambda inv: inv.get_ongrid_battery_dod(),
|
getter=lambda inv: inv.get_ongrid_battery_dod(),
|
||||||
setter=lambda inv, val: inv.set_ongrid_battery_dod(val),
|
setter=lambda inv, val: inv.set_ongrid_battery_dod(val),
|
||||||
|
@ -5,9 +5,8 @@ from goodwe import Inverter, InverterError
|
|||||||
|
|
||||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN, KEY_DEVICE_INFO, KEY_INVERTER
|
from .const import DOMAIN, KEY_DEVICE_INFO, KEY_INVERTER
|
||||||
@ -26,7 +25,7 @@ OPERATION_MODE = SelectEntityDescription(
|
|||||||
key="operation_mode",
|
key="operation_mode",
|
||||||
name="Inverter operation mode",
|
name="Inverter operation mode",
|
||||||
icon="mdi:solar-power",
|
icon="mdi:solar-power",
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ from pycec.const import (
|
|||||||
|
|
||||||
from homeassistant.components.media_player import MediaPlayerEntity
|
from homeassistant.components.media_player import MediaPlayerEntity
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
DOMAIN,
|
DOMAIN as MP_DOMAIN,
|
||||||
SUPPORT_NEXT_TRACK,
|
SUPPORT_NEXT_TRACK,
|
||||||
SUPPORT_PAUSE,
|
SUPPORT_PAUSE,
|
||||||
SUPPORT_PLAY_MEDIA,
|
SUPPORT_PLAY_MEDIA,
|
||||||
@ -48,11 +48,11 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import ATTR_NEW, CecEntity
|
from . import ATTR_NEW, DOMAIN, CecEntity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
ENTITY_ID_FORMAT = MP_DOMAIN + ".{}"
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(
|
def setup_platform(
|
||||||
@ -77,7 +77,7 @@ class CecPlayerEntity(CecEntity, MediaPlayerEntity):
|
|||||||
def __init__(self, device, logical) -> None:
|
def __init__(self, device, logical) -> None:
|
||||||
"""Initialize the HDMI device."""
|
"""Initialize the HDMI device."""
|
||||||
CecEntity.__init__(self, device, logical)
|
CecEntity.__init__(self, device, logical)
|
||||||
self.entity_id = f"{DOMAIN}.hdmi_{hex(self._logical_address)[2:]}"
|
self.entity_id = f"{MP_DOMAIN}.hdmi_{hex(self._logical_address)[2:]}"
|
||||||
|
|
||||||
def send_keypress(self, key):
|
def send_keypress(self, key):
|
||||||
"""Send keypress to CEC adapter."""
|
"""Send keypress to CEC adapter."""
|
||||||
|
@ -3,17 +3,17 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.switch import DOMAIN, SwitchEntity
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity
|
||||||
from homeassistant.const import STATE_OFF, STATE_ON
|
from homeassistant.const import STATE_OFF, STATE_ON
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import ATTR_NEW, CecEntity
|
from . import ATTR_NEW, DOMAIN, CecEntity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
ENTITY_ID_FORMAT = SWITCH_DOMAIN + ".{}"
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(
|
def setup_platform(
|
||||||
@ -38,7 +38,7 @@ class CecSwitchEntity(CecEntity, SwitchEntity):
|
|||||||
def __init__(self, device, logical) -> None:
|
def __init__(self, device, logical) -> None:
|
||||||
"""Initialize the HDMI device."""
|
"""Initialize the HDMI device."""
|
||||||
CecEntity.__init__(self, device, logical)
|
CecEntity.__init__(self, device, logical)
|
||||||
self.entity_id = f"{DOMAIN}.hdmi_{hex(self._logical_address)[2:]}"
|
self.entity_id = f"{SWITCH_DOMAIN}.hdmi_{hex(self._logical_address)[2:]}"
|
||||||
|
|
||||||
def turn_on(self, **kwargs) -> None:
|
def turn_on(self, **kwargs) -> None:
|
||||||
"""Turn device on."""
|
"""Turn device on."""
|
||||||
|
@ -16,13 +16,12 @@ from homeassistant.const import (
|
|||||||
DEVICE_CLASS_GAS,
|
DEVICE_CLASS_GAS,
|
||||||
DEVICE_CLASS_POWER,
|
DEVICE_CLASS_POWER,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
POWER_WATT,
|
POWER_WATT,
|
||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
@ -37,19 +36,19 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = (
|
|||||||
key="smr_version",
|
key="smr_version",
|
||||||
name="DSMR Version",
|
name="DSMR Version",
|
||||||
icon="mdi:counter",
|
icon="mdi:counter",
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="meter_model",
|
key="meter_model",
|
||||||
name="Smart Meter Model",
|
name="Smart Meter Model",
|
||||||
icon="mdi:gauge",
|
icon="mdi:gauge",
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="wifi_ssid",
|
key="wifi_ssid",
|
||||||
name="Wifi SSID",
|
name="Wifi SSID",
|
||||||
icon="mdi:wifi",
|
icon="mdi:wifi",
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="wifi_strength",
|
key="wifi_strength",
|
||||||
@ -57,7 +56,7 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = (
|
|||||||
icon="mdi:wifi",
|
icon="mdi:wifi",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Philips Hue",
|
"name": "Philips Hue",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/hue",
|
"documentation": "https://www.home-assistant.io/integrations/hue",
|
||||||
"requirements": ["aiohue==4.0.1"],
|
"requirements": ["aiohue==4.1.2"],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"manufacturer": "Royal Philips Electronics",
|
"manufacturer": "Royal Philips Electronics",
|
||||||
|
@ -5,7 +5,11 @@ from typing import Any
|
|||||||
|
|
||||||
from aiohue.v2 import HueBridgeV2
|
from aiohue.v2 import HueBridgeV2
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.controllers.scenes import Scene as HueScene, ScenesController
|
from aiohue.v2.controllers.scenes import (
|
||||||
|
Scene as HueScene,
|
||||||
|
ScenePut as HueScenePut,
|
||||||
|
ScenesController,
|
||||||
|
)
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.scene import ATTR_TRANSITION, Scene as SceneEntity
|
from homeassistant.components.scene import ATTR_TRANSITION, Scene as SceneEntity
|
||||||
@ -131,7 +135,7 @@ class HueSceneEntity(HueBaseEntity, SceneEntity):
|
|||||||
await self.bridge.async_request_call(
|
await self.bridge.async_request_call(
|
||||||
self.controller.update,
|
self.controller.update,
|
||||||
self.resource.id,
|
self.resource.id,
|
||||||
HueScene(self.resource.id, speed=speed / 100),
|
HueScenePut(speed=speed / 100),
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.bridge.async_request_call(
|
await self.bridge.async_request_call(
|
||||||
|
@ -5,8 +5,12 @@ from typing import Any, Union
|
|||||||
|
|
||||||
from aiohue.v2 import HueBridgeV2
|
from aiohue.v2 import HueBridgeV2
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.controllers.sensors import LightLevelController, MotionController
|
from aiohue.v2.controllers.sensors import (
|
||||||
from aiohue.v2.models.resource import SensingService
|
LightLevel,
|
||||||
|
LightLevelController,
|
||||||
|
Motion,
|
||||||
|
MotionController,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
|
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -20,6 +24,8 @@ from .v2.entity import HueBaseEntity
|
|||||||
|
|
||||||
ControllerType = Union[LightLevelController, MotionController]
|
ControllerType = Union[LightLevelController, MotionController]
|
||||||
|
|
||||||
|
SensingService = Union[LightLevel, Motion]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -4,13 +4,13 @@ from __future__ import annotations
|
|||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
from aiohue.v2 import HueBridgeV2
|
from aiohue.v2 import HueBridgeV2
|
||||||
from aiohue.v2.controllers.config import EntertainmentConfigurationController
|
from aiohue.v2.controllers.config import (
|
||||||
|
EntertainmentConfiguration,
|
||||||
|
EntertainmentConfigurationController,
|
||||||
|
)
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.controllers.sensors import MotionController
|
from aiohue.v2.controllers.sensors import MotionController
|
||||||
from aiohue.v2.models.entertainment import (
|
from aiohue.v2.models.entertainment_configuration import EntertainmentStatus
|
||||||
EntertainmentConfiguration,
|
|
||||||
EntertainmentStatus,
|
|
||||||
)
|
|
||||||
from aiohue.v2.models.motion import Motion
|
from aiohue.v2.models.motion import Motion
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
@ -109,4 +109,4 @@ class HueEntertainmentActiveSensor(HueBinarySensorBase):
|
|||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""Return sensor name."""
|
"""Return sensor name."""
|
||||||
type_title = self.resource.type.value.replace("_", " ").title()
|
type_title = self.resource.type.value.replace("_", " ").title()
|
||||||
return f"{self.resource.name}: {type_title}"
|
return f"{self.resource.metadata.name}: {type_title}"
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
"""Generic Hue Entity Model."""
|
"""Generic Hue Entity Model."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Union
|
||||||
|
|
||||||
from aiohue.v2.controllers.base import BaseResourcesController
|
from aiohue.v2.controllers.base import BaseResourcesController
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.models.clip import CLIPResource
|
|
||||||
from aiohue.v2.models.connectivity import ConnectivityServiceStatus
|
|
||||||
from aiohue.v2.models.resource import ResourceTypes
|
from aiohue.v2.models.resource import ResourceTypes
|
||||||
|
from aiohue.v2.models.zigbee_connectivity import ConnectivityServiceStatus
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||||
@ -14,6 +15,16 @@ from homeassistant.helpers.entity_registry import async_get as async_get_entity_
|
|||||||
from ..bridge import HueBridge
|
from ..bridge import HueBridge
|
||||||
from ..const import CONF_IGNORE_AVAILABILITY, DOMAIN
|
from ..const import CONF_IGNORE_AVAILABILITY, DOMAIN
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from aiohue.v2.models.device_power import DevicePower
|
||||||
|
from aiohue.v2.models.grouped_light import GroupedLight
|
||||||
|
from aiohue.v2.models.light import Light
|
||||||
|
from aiohue.v2.models.light_level import LightLevel
|
||||||
|
from aiohue.v2.models.motion import Motion
|
||||||
|
|
||||||
|
HueResource = Union[Light, DevicePower, GroupedLight, LightLevel, Motion]
|
||||||
|
|
||||||
|
|
||||||
RESOURCE_TYPE_NAMES = {
|
RESOURCE_TYPE_NAMES = {
|
||||||
# a simple mapping of hue resource type to Hass name
|
# a simple mapping of hue resource type to Hass name
|
||||||
ResourceTypes.LIGHT_LEVEL: "Illuminance",
|
ResourceTypes.LIGHT_LEVEL: "Illuminance",
|
||||||
@ -30,7 +41,7 @@ class HueBaseEntity(Entity):
|
|||||||
self,
|
self,
|
||||||
bridge: HueBridge,
|
bridge: HueBridge,
|
||||||
controller: BaseResourcesController,
|
controller: BaseResourcesController,
|
||||||
resource: CLIPResource,
|
resource: HueResource,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a generic Hue resource entity."""
|
"""Initialize a generic Hue resource entity."""
|
||||||
self.bridge = bridge
|
self.bridge = bridge
|
||||||
@ -122,7 +133,7 @@ class HueBaseEntity(Entity):
|
|||||||
# used in subclasses
|
# used in subclasses
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_event(self, event_type: EventType, resource: CLIPResource) -> None:
|
def _handle_event(self, event_type: EventType, resource: HueResource) -> None:
|
||||||
"""Handle status event for this resource (or it's parent)."""
|
"""Handle status event for this resource (or it's parent)."""
|
||||||
if event_type == EventType.RESOURCE_DELETED and resource.id == self.resource.id:
|
if event_type == EventType.RESOURCE_DELETED and resource.id == self.resource.id:
|
||||||
self.logger.debug("Received delete for %s", self.entity_id)
|
self.logger.debug("Received delete for %s", self.entity_id)
|
||||||
|
@ -7,7 +7,7 @@ from typing import Any
|
|||||||
from aiohue.v2 import HueBridgeV2
|
from aiohue.v2 import HueBridgeV2
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.controllers.groups import GroupedLight, Room, Zone
|
from aiohue.v2.controllers.groups import GroupedLight, Room, Zone
|
||||||
from aiohue.v2.models.feature import DynamicsFeatureStatus
|
from aiohue.v2.models.feature import DynamicStatus
|
||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
@ -283,7 +283,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
|
|||||||
total_brightness += dimming.brightness
|
total_brightness += dimming.brightness
|
||||||
if (
|
if (
|
||||||
light.dynamics
|
light.dynamics
|
||||||
and light.dynamics.status == DynamicsFeatureStatus.DYNAMIC_PALETTE
|
and light.dynamics.status == DynamicStatus.DYNAMIC_PALETTE
|
||||||
):
|
):
|
||||||
lights_in_dynamic_mode += 1
|
lights_in_dynamic_mode += 1
|
||||||
|
|
||||||
|
@ -12,10 +12,10 @@ from aiohue.v2.controllers.sensors import (
|
|||||||
TemperatureController,
|
TemperatureController,
|
||||||
ZigbeeConnectivityController,
|
ZigbeeConnectivityController,
|
||||||
)
|
)
|
||||||
from aiohue.v2.models.connectivity import ZigbeeConnectivity
|
|
||||||
from aiohue.v2.models.device_power import DevicePower
|
from aiohue.v2.models.device_power import DevicePower
|
||||||
from aiohue.v2.models.light_level import LightLevel
|
from aiohue.v2.models.light_level import LightLevel
|
||||||
from aiohue.v2.models.temperature import Temperature
|
from aiohue.v2.models.temperature import Temperature
|
||||||
|
from aiohue.v2.models.zigbee_connectivity import ZigbeeConnectivity
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
|
@ -8,8 +8,8 @@ write_coil:
|
|||||||
required: true
|
required: true
|
||||||
selector:
|
selector:
|
||||||
number:
|
number:
|
||||||
min: 1
|
min: 0
|
||||||
max: 255
|
max: 65535
|
||||||
state:
|
state:
|
||||||
name: State
|
name: State
|
||||||
description: State to write.
|
description: State to write.
|
||||||
@ -42,8 +42,8 @@ write_register:
|
|||||||
required: true
|
required: true
|
||||||
selector:
|
selector:
|
||||||
number:
|
number:
|
||||||
min: 1
|
min: 0
|
||||||
max: 255
|
max: 65535
|
||||||
unit:
|
unit:
|
||||||
name: Unit
|
name: Unit
|
||||||
description: Address of the modbus unit.
|
description: Address of the modbus unit.
|
||||||
|
@ -127,6 +127,15 @@ class NestCamera(Camera):
|
|||||||
return STREAM_TYPE_WEB_RTC
|
return STREAM_TYPE_WEB_RTC
|
||||||
return super().frontend_stream_type
|
return super().frontend_stream_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Return True if entity is available."""
|
||||||
|
# Cameras are marked unavailable on stream errors in #54659 however nest streams have
|
||||||
|
# a high error rate (#60353). Given nest streams are so flaky, marking the stream
|
||||||
|
# unavailable has other side effects like not showing the camera image which sometimes
|
||||||
|
# are still able to work. Until the streams are fixed, just leave the streams as available.
|
||||||
|
return True
|
||||||
|
|
||||||
async def stream_source(self) -> str | None:
|
async def stream_source(self) -> str | None:
|
||||||
"""Return the source of the stream."""
|
"""Return the source of the stream."""
|
||||||
if not self.supported_features & SUPPORT_STREAM:
|
if not self.supported_features & SUPPORT_STREAM:
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
|
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .base import ONVIFBaseEntity
|
from .base import ONVIFBaseEntity
|
||||||
@ -25,7 +25,7 @@ class RebootButton(ONVIFBaseEntity, ButtonEntity):
|
|||||||
"""Defines a ONVIF reboot button."""
|
"""Defines a ONVIF reboot button."""
|
||||||
|
|
||||||
_attr_device_class = ButtonDeviceClass.RESTART
|
_attr_device_class = ButtonDeviceClass.RESTART
|
||||||
_attr_entity_category = ENTITY_CATEGORY_CONFIG
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
|
|
||||||
def __init__(self, device: ONVIFDevice) -> None:
|
def __init__(self, device: ONVIFDevice) -> None:
|
||||||
"""Initialize the button entity."""
|
"""Initialize the button entity."""
|
||||||
|
@ -148,9 +148,12 @@ class PhilipsTVDataUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
@property
|
@property
|
||||||
def unique_id(self) -> str:
|
def unique_id(self) -> str:
|
||||||
"""Return the system descriptor."""
|
"""Return the system descriptor."""
|
||||||
assert self.config_entry
|
entry: ConfigEntry = self.config_entry
|
||||||
assert self.config_entry.unique_id
|
assert entry
|
||||||
return self.config_entry.unique_id
|
if entry.unique_id:
|
||||||
|
return entry.unique_id
|
||||||
|
assert entry.entry_id
|
||||||
|
return entry.entry_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _notify_wanted(self):
|
def _notify_wanted(self):
|
||||||
|
@ -122,8 +122,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
LOGGER.exception("Unexpected exception")
|
LOGGER.exception("Unexpected exception")
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
else:
|
else:
|
||||||
|
if serialnumber := hub.system.get("serialnumber"):
|
||||||
await self.async_set_unique_id(hub.system["serialnumber"])
|
await self.async_set_unique_id(serialnumber)
|
||||||
self._abort_if_unique_id_configured()
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
self._current[CONF_SYSTEM] = hub.system
|
self._current[CONF_SYSTEM] = hub.system
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -109,20 +108,12 @@ class I2CHatBinarySensor(BinarySensorEntity):
|
|||||||
self._device_class = device_class
|
self._device_class = device_class
|
||||||
self._state = self.I2C_HATS_MANAGER.read_di(self._address, self._channel)
|
self._state = self.I2C_HATS_MANAGER.read_di(self._address, self._channel)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
|
||||||
"""Register callbacks."""
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert self.I2C_HATS_MANAGER
|
|
||||||
|
|
||||||
def online_callback():
|
def online_callback():
|
||||||
"""Call fired when board is online."""
|
"""Call fired when board is online."""
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(
|
self.I2C_HATS_MANAGER.register_online_callback(
|
||||||
self.I2C_HATS_MANAGER.register_online_callback,
|
self._address, self._channel, online_callback
|
||||||
self._address,
|
|
||||||
self._channel,
|
|
||||||
online_callback,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def edge_callback(state):
|
def edge_callback(state):
|
||||||
@ -130,11 +121,8 @@ class I2CHatBinarySensor(BinarySensorEntity):
|
|||||||
self._state = state
|
self._state = state
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(
|
self.I2C_HATS_MANAGER.register_di_callback(
|
||||||
self.I2C_HATS_MANAGER.register_di_callback,
|
self._address, self._channel, edge_callback
|
||||||
self._address,
|
|
||||||
self._channel,
|
|
||||||
edge_callback,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -101,7 +100,6 @@ class I2CHatSwitch(SwitchEntity):
|
|||||||
self._channel = channel
|
self._channel = channel
|
||||||
self._name = name or DEVICE_DEFAULT_NAME
|
self._name = name or DEVICE_DEFAULT_NAME
|
||||||
self._invert_logic = invert_logic
|
self._invert_logic = invert_logic
|
||||||
self._state = initial_state
|
|
||||||
if initial_state is not None:
|
if initial_state is not None:
|
||||||
if self._invert_logic:
|
if self._invert_logic:
|
||||||
state = not initial_state
|
state = not initial_state
|
||||||
@ -109,27 +107,14 @@ class I2CHatSwitch(SwitchEntity):
|
|||||||
state = initial_state
|
state = initial_state
|
||||||
self.I2C_HATS_MANAGER.write_dq(self._address, self._channel, state)
|
self.I2C_HATS_MANAGER.write_dq(self._address, self._channel, state)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
def online_callback():
|
||||||
"""Register callbacks."""
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert self.I2C_HATS_MANAGER
|
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(
|
|
||||||
self.I2C_HATS_MANAGER.register_online_callback,
|
|
||||||
self._address,
|
|
||||||
self._channel,
|
|
||||||
self.online_callback,
|
|
||||||
)
|
|
||||||
|
|
||||||
def online_callback(self):
|
|
||||||
"""Call fired when board is online."""
|
"""Call fired when board is online."""
|
||||||
try:
|
|
||||||
self._state = self.I2C_HATS_MANAGER.read_dq(self._address, self._channel)
|
|
||||||
except I2CHatsException as ex:
|
|
||||||
_LOGGER.error(self._log_message(f"Is ON check failed, {ex!s}"))
|
|
||||||
self._state = False
|
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
self.I2C_HATS_MANAGER.register_online_callback(
|
||||||
|
self._address, self._channel, online_callback
|
||||||
|
)
|
||||||
|
|
||||||
def _log_message(self, message):
|
def _log_message(self, message):
|
||||||
"""Create log message."""
|
"""Create log message."""
|
||||||
string = f"{self._name} "
|
string = f"{self._name} "
|
||||||
@ -150,7 +135,12 @@ class I2CHatSwitch(SwitchEntity):
|
|||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self._state != self._invert_logic
|
try:
|
||||||
|
state = self.I2C_HATS_MANAGER.read_dq(self._address, self._channel)
|
||||||
|
return state != self._invert_logic
|
||||||
|
except I2CHatsException as ex:
|
||||||
|
_LOGGER.error(self._log_message(f"Is ON check failed, {ex!s}"))
|
||||||
|
return False
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
|
@ -23,7 +23,7 @@ UID_POSTFIX = "01400"
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
_T = TypeVar("_T", "SonosSpeaker", "SonosEntity")
|
_T = TypeVar("_T", bound="SonosSpeaker | SonosEntity")
|
||||||
_R = TypeVar("_R")
|
_R = TypeVar("_R")
|
||||||
_P = ParamSpec("_P")
|
_P = ParamSpec("_P")
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from soco.exceptions import SoCoException, SoCoSlaveException, SoCoUPnPException
|
from soco.exceptions import SoCoException, SoCoSlaveException, SoCoUPnPException
|
||||||
|
|
||||||
@ -342,20 +343,20 @@ class SonosAlarmEntity(SonosEntity, SwitchEntity):
|
|||||||
ATTR_INCLUDE_LINKED_ZONES: self.alarm.include_linked_zones,
|
ATTR_INCLUDE_LINKED_ZONES: self.alarm.include_linked_zones,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs) -> None:
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn alarm switch on."""
|
"""Turn alarm switch on."""
|
||||||
await self.async_handle_switch_on_off(turn_on=True)
|
self._handle_switch_on_off(turn_on=True)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs) -> None:
|
def turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn alarm switch off."""
|
"""Turn alarm switch off."""
|
||||||
await self.async_handle_switch_on_off(turn_on=False)
|
self._handle_switch_on_off(turn_on=False)
|
||||||
|
|
||||||
async def async_handle_switch_on_off(self, turn_on: bool) -> None:
|
def _handle_switch_on_off(self, turn_on: bool) -> None:
|
||||||
"""Handle turn on/off of alarm switch."""
|
"""Handle turn on/off of alarm switch."""
|
||||||
try:
|
try:
|
||||||
_LOGGER.debug("Toggling the state of %s", self.entity_id)
|
_LOGGER.debug("Toggling the state of %s", self.entity_id)
|
||||||
self.alarm.enabled = turn_on
|
self.alarm.enabled = turn_on
|
||||||
await self.hass.async_add_executor_job(self.alarm.save)
|
self.alarm.save()
|
||||||
except (OSError, SoCoException, SoCoUPnPException) as exc:
|
except (OSError, SoCoException, SoCoUPnPException) as exc:
|
||||||
_LOGGER.error("Could not update %s: %s", self.entity_id, exc)
|
_LOGGER.error("Could not update %s: %s", self.entity_id, exc)
|
||||||
|
|
||||||
|
@ -121,6 +121,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
raise ConfigEntryNotReady from err
|
raise ConfigEntryNotReady from err
|
||||||
|
|
||||||
async def _update_devices() -> list[dict[str, Any]]:
|
async def _update_devices() -> list[dict[str, Any]]:
|
||||||
|
if not session.valid_token:
|
||||||
|
await session.async_ensure_token_valid()
|
||||||
|
await hass.async_add_executor_job(
|
||||||
|
spotify.set_auth, session.token["access_token"]
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
devices: dict[str, Any] | None = await hass.async_add_executor_job(
|
devices: dict[str, Any] | None = await hass.async_add_executor_job(
|
||||||
spotify.devices
|
spotify.devices
|
||||||
|
@ -515,9 +515,7 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
|
|||||||
run_coroutine_threadsafe(
|
run_coroutine_threadsafe(
|
||||||
self._session.async_ensure_token_valid(), self.hass.loop
|
self._session.async_ensure_token_valid(), self.hass.loop
|
||||||
).result()
|
).result()
|
||||||
self._spotify_data[DATA_SPOTIFY_CLIENT] = Spotify(
|
self._spotify.set_auth(auth=self._session.token["access_token"])
|
||||||
auth=self._session.token["access_token"]
|
|
||||||
)
|
|
||||||
|
|
||||||
current = self._spotify.current_playback()
|
current = self._spotify.current_playback()
|
||||||
self._currently_playing = current or {}
|
self._currently_playing = current or {}
|
||||||
@ -581,7 +579,11 @@ async def async_browse_media_internal(
|
|||||||
partial(library_payload, can_play_artist=can_play_artist)
|
partial(library_payload, can_play_artist=can_play_artist)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not session.valid_token:
|
||||||
await session.async_ensure_token_valid()
|
await session.async_ensure_token_valid()
|
||||||
|
await hass.async_add_executor_job(
|
||||||
|
spotify.set_auth, session.token["access_token"]
|
||||||
|
)
|
||||||
|
|
||||||
# Strip prefix
|
# Strip prefix
|
||||||
media_content_type = media_content_type[len(MEDIA_PLAYER_PREFIX) :]
|
media_content_type = media_content_type[len(MEDIA_PLAYER_PREFIX) :]
|
||||||
|
@ -342,7 +342,9 @@ class Stream:
|
|||||||
stream_state.discontinuity()
|
stream_state.discontinuity()
|
||||||
if not self.keepalive or self._thread_quit.is_set():
|
if not self.keepalive or self._thread_quit.is_set():
|
||||||
if self._fast_restart_once:
|
if self._fast_restart_once:
|
||||||
# The stream source is updated, restart without any delay.
|
# The stream source is updated, restart without any delay and reset the retry
|
||||||
|
# backoff for the new url.
|
||||||
|
wait_timeout = 0
|
||||||
self._fast_restart_once = False
|
self._fast_restart_once = False
|
||||||
self._thread_quit.clear()
|
self._thread_quit.clear()
|
||||||
continue
|
continue
|
||||||
|
@ -8,7 +8,7 @@ DATA_BRIDGE = "bridge"
|
|||||||
DATA_DEVICE = "device"
|
DATA_DEVICE = "device"
|
||||||
DATA_DISCOVERY = "discovery"
|
DATA_DISCOVERY = "discovery"
|
||||||
|
|
||||||
DISCOVERY_TIME_SEC = 6
|
DISCOVERY_TIME_SEC = 12
|
||||||
|
|
||||||
SIGNAL_DEVICE_ADD = "switcher_device_add"
|
SIGNAL_DEVICE_ADD = "switcher_device_add"
|
||||||
|
|
||||||
@ -19,4 +19,4 @@ SERVICE_SET_AUTO_OFF_NAME = "set_auto_off"
|
|||||||
SERVICE_TURN_ON_WITH_TIMER_NAME = "turn_on_with_timer"
|
SERVICE_TURN_ON_WITH_TIMER_NAME = "turn_on_with_timer"
|
||||||
|
|
||||||
# Defines the maximum interval device must send an update before it marked unavailable
|
# Defines the maximum interval device must send an update before it marked unavailable
|
||||||
MAX_UPDATE_INTERVAL_SEC = 20
|
MAX_UPDATE_INTERVAL_SEC = 30
|
||||||
|
@ -158,7 +158,10 @@ async def async_setup_entry(
|
|||||||
device = hass_data.device_manager.device_map[device_id]
|
device = hass_data.device_manager.device_map[device_id]
|
||||||
if descriptions := COVERS.get(device.category):
|
if descriptions := COVERS.get(device.category):
|
||||||
for description in descriptions:
|
for description in descriptions:
|
||||||
if description.key in device.status:
|
if (
|
||||||
|
description.key in device.function
|
||||||
|
or description.key in device.status_range
|
||||||
|
):
|
||||||
entities.append(
|
entities.append(
|
||||||
TuyaCoverEntity(
|
TuyaCoverEntity(
|
||||||
device, hass_data.device_manager, description
|
device, hass_data.device_manager, description
|
||||||
|
@ -182,8 +182,6 @@ class TariffSelect(RestoreEntity):
|
|||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Run when entity about to be added."""
|
"""Run when entity about to be added."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
if self._current_tariff is not None:
|
|
||||||
return
|
|
||||||
|
|
||||||
state = await self.async_get_last_state()
|
state = await self.async_get_last_state()
|
||||||
if not state or state.state not in self._tariffs:
|
if not state or state.state not in self._tariffs:
|
||||||
|
@ -32,6 +32,7 @@ from homeassistant.helpers.event import (
|
|||||||
async_track_state_change_event,
|
async_track_state_change_event,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
from homeassistant.helpers.template import is_number
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
@ -166,13 +167,10 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
|
|||||||
self._parent_meter = parent_meter
|
self._parent_meter = parent_meter
|
||||||
self._sensor_source_id = source_entity
|
self._sensor_source_id = source_entity
|
||||||
self._state = None
|
self._state = None
|
||||||
self._last_period = 0
|
self._last_period = Decimal(0)
|
||||||
self._last_reset = dt_util.utcnow()
|
self._last_reset = dt_util.utcnow()
|
||||||
self._collecting = None
|
self._collecting = None
|
||||||
if name:
|
|
||||||
self._name = name
|
self._name = name
|
||||||
else:
|
|
||||||
self._name = f"{source_entity} meter"
|
|
||||||
self._unit_of_measurement = None
|
self._unit_of_measurement = None
|
||||||
self._period = meter_type
|
self._period = meter_type
|
||||||
if meter_type is not None:
|
if meter_type is not None:
|
||||||
@ -231,8 +229,6 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
|
|||||||
return
|
return
|
||||||
self._state += adjustment
|
self._state += adjustment
|
||||||
|
|
||||||
except ValueError as err:
|
|
||||||
_LOGGER.warning("While processing state changes: %s", err)
|
|
||||||
except DecimalException as err:
|
except DecimalException as err:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Invalid state (%s > %s): %s", old_state.state, new_state.state, err
|
"Invalid state (%s > %s): %s", old_state.state, new_state.state, err
|
||||||
@ -282,7 +278,7 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
|
|||||||
return
|
return
|
||||||
_LOGGER.debug("Reset utility meter <%s>", self.entity_id)
|
_LOGGER.debug("Reset utility meter <%s>", self.entity_id)
|
||||||
self._last_reset = dt_util.utcnow()
|
self._last_reset = dt_util.utcnow()
|
||||||
self._last_period = str(self._state)
|
self._last_period = Decimal(self._state) if self._state else Decimal(0)
|
||||||
self._state = 0
|
self._state = 0
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@ -319,9 +315,10 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
|
|||||||
ATTR_UNIT_OF_MEASUREMENT
|
ATTR_UNIT_OF_MEASUREMENT
|
||||||
)
|
)
|
||||||
self._last_period = (
|
self._last_period = (
|
||||||
float(state.attributes.get(ATTR_LAST_PERIOD))
|
Decimal(state.attributes[ATTR_LAST_PERIOD])
|
||||||
if state.attributes.get(ATTR_LAST_PERIOD)
|
if state.attributes.get(ATTR_LAST_PERIOD)
|
||||||
else 0
|
and is_number(state.attributes[ATTR_LAST_PERIOD])
|
||||||
|
else Decimal(0)
|
||||||
)
|
)
|
||||||
self._last_reset = dt_util.as_utc(
|
self._last_reset = dt_util.as_utc(
|
||||||
dt_util.parse_datetime(state.attributes.get(ATTR_LAST_RESET))
|
dt_util.parse_datetime(state.attributes.get(ATTR_LAST_RESET))
|
||||||
@ -399,7 +396,7 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
|
|||||||
state_attr = {
|
state_attr = {
|
||||||
ATTR_SOURCE_ID: self._sensor_source_id,
|
ATTR_SOURCE_ID: self._sensor_source_id,
|
||||||
ATTR_STATUS: PAUSED if self._collecting is None else COLLECTING,
|
ATTR_STATUS: PAUSED if self._collecting is None else COLLECTING,
|
||||||
ATTR_LAST_PERIOD: self._last_period,
|
ATTR_LAST_PERIOD: str(self._last_period),
|
||||||
}
|
}
|
||||||
if self._period is not None:
|
if self._period is not None:
|
||||||
state_attr[ATTR_PERIOD] = self._period
|
state_attr[ATTR_PERIOD] = self._period
|
||||||
|
@ -14,8 +14,8 @@ import requests
|
|||||||
|
|
||||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import ViCareRequiredKeysMixin
|
from . import ViCareRequiredKeysMixin
|
||||||
@ -36,7 +36,7 @@ BUTTON_DESCRIPTIONS: tuple[ViCareButtonEntityDescription, ...] = (
|
|||||||
key=BUTTON_DHW_ACTIVATE_ONETIME_CHARGE,
|
key=BUTTON_DHW_ACTIVATE_ONETIME_CHARGE,
|
||||||
name="Activate one-time charge",
|
name="Activate one-time charge",
|
||||||
icon="mdi:shower-head",
|
icon="mdi:shower-head",
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
value_getter=lambda api: api.activateOneTimeCharge(),
|
value_getter=lambda api: api.activateOneTimeCharge(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -145,7 +145,7 @@ class VizioDevice(MediaPlayerEntity):
|
|||||||
self._volume_step = config_entry.options[CONF_VOLUME_STEP]
|
self._volume_step = config_entry.options[CONF_VOLUME_STEP]
|
||||||
self._current_input = None
|
self._current_input = None
|
||||||
self._current_app_config = None
|
self._current_app_config = None
|
||||||
self._app_name = None
|
self._attr_app_name = None
|
||||||
self._available_inputs = []
|
self._available_inputs = []
|
||||||
self._available_apps = []
|
self._available_apps = []
|
||||||
self._all_apps = apps_coordinator.data if apps_coordinator else None
|
self._all_apps = apps_coordinator.data if apps_coordinator else None
|
||||||
@ -209,7 +209,7 @@ class VizioDevice(MediaPlayerEntity):
|
|||||||
self._attr_volume_level = None
|
self._attr_volume_level = None
|
||||||
self._attr_is_volume_muted = None
|
self._attr_is_volume_muted = None
|
||||||
self._current_input = None
|
self._current_input = None
|
||||||
self._app_name = None
|
self._attr_app_name = None
|
||||||
self._current_app_config = None
|
self._current_app_config = None
|
||||||
self._attr_sound_mode = None
|
self._attr_sound_mode = None
|
||||||
return
|
return
|
||||||
@ -265,13 +265,13 @@ class VizioDevice(MediaPlayerEntity):
|
|||||||
log_api_exception=False
|
log_api_exception=False
|
||||||
)
|
)
|
||||||
|
|
||||||
self._app_name = find_app_name(
|
self._attr_app_name = find_app_name(
|
||||||
self._current_app_config,
|
self._current_app_config,
|
||||||
[APP_HOME, *self._all_apps, *self._additional_app_configs],
|
[APP_HOME, *self._all_apps, *self._additional_app_configs],
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._app_name == NO_APP_RUNNING:
|
if self._attr_app_name == NO_APP_RUNNING:
|
||||||
self._app_name = None
|
self._attr_app_name = None
|
||||||
|
|
||||||
def _get_additional_app_names(self) -> list[dict[str, Any]]:
|
def _get_additional_app_names(self) -> list[dict[str, Any]]:
|
||||||
"""Return list of additional apps that were included in configuration.yaml."""
|
"""Return list of additional apps that were included in configuration.yaml."""
|
||||||
@ -337,8 +337,8 @@ class VizioDevice(MediaPlayerEntity):
|
|||||||
@property
|
@property
|
||||||
def source(self) -> str | None:
|
def source(self) -> str | None:
|
||||||
"""Return current input of the device."""
|
"""Return current input of the device."""
|
||||||
if self._app_name is not None and self._current_input in INPUT_APPS:
|
if self._attr_app_name is not None and self._current_input in INPUT_APPS:
|
||||||
return self._app_name
|
return self._attr_app_name
|
||||||
|
|
||||||
return self._current_input
|
return self._current_input
|
||||||
|
|
||||||
@ -364,14 +364,6 @@ class VizioDevice(MediaPlayerEntity):
|
|||||||
|
|
||||||
return self._available_inputs
|
return self._available_inputs
|
||||||
|
|
||||||
@property
|
|
||||||
def app_name(self) -> str | None:
|
|
||||||
"""Return the name of the current app."""
|
|
||||||
if self.source == self._app_name:
|
|
||||||
return self._app_name
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def app_id(self) -> str | None:
|
def app_id(self) -> str | None:
|
||||||
"""Return the ID of the current app if it is unknown by pyvizio."""
|
"""Return the ID of the current app if it is unknown by pyvizio."""
|
||||||
|
@ -8,9 +8,10 @@ from typing import Any
|
|||||||
|
|
||||||
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
|
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_DIAGNOSTIC, Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .core import discovery
|
from .core import discovery
|
||||||
@ -96,7 +97,7 @@ class ZHAIdentifyButton(ZHAButton):
|
|||||||
return cls(unique_id, zha_device, channels, **kwargs)
|
return cls(unique_id, zha_device, channels, **kwargs)
|
||||||
|
|
||||||
_attr_device_class: ButtonDeviceClass = ButtonDeviceClass.UPDATE
|
_attr_device_class: ButtonDeviceClass = ButtonDeviceClass.UPDATE
|
||||||
_attr_entity_category = ENTITY_CATEGORY_DIAGNOSTIC
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
_command_name = "identify"
|
_command_name = "identify"
|
||||||
|
|
||||||
def get_args(self) -> list[Any]:
|
def get_args(self) -> list[Any]:
|
||||||
|
@ -8,9 +8,10 @@ from zigpy.zcl.clusters.security import IasWd
|
|||||||
|
|
||||||
from homeassistant.components.select import SelectEntity
|
from homeassistant.components.select import SelectEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG, STATE_UNKNOWN, Platform
|
from homeassistant.const import STATE_UNKNOWN, Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .core import discovery
|
from .core import discovery
|
||||||
@ -46,7 +47,7 @@ async def async_setup_entry(
|
|||||||
class ZHAEnumSelectEntity(ZhaEntity, SelectEntity):
|
class ZHAEnumSelectEntity(ZhaEntity, SelectEntity):
|
||||||
"""Representation of a ZHA select entity."""
|
"""Representation of a ZHA select entity."""
|
||||||
|
|
||||||
_attr_entity_category = ENTITY_CATEGORY_CONFIG
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
_enum: Enum = None
|
_enum: Enum = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -25,7 +25,6 @@ from homeassistant.const import (
|
|||||||
ELECTRIC_CURRENT_AMPERE,
|
ELECTRIC_CURRENT_AMPERE,
|
||||||
ELECTRIC_POTENTIAL_VOLT,
|
ELECTRIC_POTENTIAL_VOLT,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
|
||||||
LIGHT_LUX,
|
LIGHT_LUX,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
POWER_VOLT_AMPERE,
|
POWER_VOLT_AMPERE,
|
||||||
@ -699,7 +698,7 @@ class RSSISensor(Sensor, id_suffix="rssi"):
|
|||||||
|
|
||||||
_state_class: SensorStateClass = SensorStateClass.MEASUREMENT
|
_state_class: SensorStateClass = SensorStateClass.MEASUREMENT
|
||||||
_device_class: SensorDeviceClass = SensorDeviceClass.SIGNAL_STRENGTH
|
_device_class: SensorDeviceClass = SensorDeviceClass.SIGNAL_STRENGTH
|
||||||
_attr_entity_category = ENTITY_CATEGORY_DIAGNOSTIC
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
_attr_entity_registry_enabled_default = False
|
_attr_entity_registry_enabled_default = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -7,7 +7,7 @@ from .backports.enum import StrEnum
|
|||||||
|
|
||||||
MAJOR_VERSION: Final = 2022
|
MAJOR_VERSION: Final = 2022
|
||||||
MINOR_VERSION: Final = 2
|
MINOR_VERSION: Final = 2
|
||||||
PATCH_VERSION: Final = "6"
|
PATCH_VERSION: Final = "7"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
||||||
|
@ -114,7 +114,7 @@ adext==0.4.2
|
|||||||
adguardhome==0.5.1
|
adguardhome==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.advantage_air
|
# homeassistant.components.advantage_air
|
||||||
advantage_air==0.2.5
|
advantage_air==0.3.0
|
||||||
|
|
||||||
# homeassistant.components.frontier_silicon
|
# homeassistant.components.frontier_silicon
|
||||||
afsapi==0.0.4
|
afsapi==0.0.4
|
||||||
@ -191,7 +191,7 @@ aiohomekit==0.6.11
|
|||||||
aiohttp_cors==0.7.0
|
aiohttp_cors==0.7.0
|
||||||
|
|
||||||
# homeassistant.components.hue
|
# homeassistant.components.hue
|
||||||
aiohue==4.0.1
|
aiohue==4.1.2
|
||||||
|
|
||||||
# homeassistant.components.homewizard
|
# homeassistant.components.homewizard
|
||||||
aiohwenergy==0.8.0
|
aiohwenergy==0.8.0
|
||||||
@ -681,7 +681,7 @@ fjaraskupan==1.0.2
|
|||||||
flipr-api==1.4.1
|
flipr-api==1.4.1
|
||||||
|
|
||||||
# homeassistant.components.flux_led
|
# homeassistant.components.flux_led
|
||||||
flux_led==0.28.22
|
flux_led==0.28.26
|
||||||
|
|
||||||
# homeassistant.components.homekit
|
# homeassistant.components.homekit
|
||||||
fnvhash==0.1.0
|
fnvhash==0.1.0
|
||||||
|
@ -70,7 +70,7 @@ adext==0.4.2
|
|||||||
adguardhome==0.5.1
|
adguardhome==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.advantage_air
|
# homeassistant.components.advantage_air
|
||||||
advantage_air==0.2.5
|
advantage_air==0.3.0
|
||||||
|
|
||||||
# homeassistant.components.agent_dvr
|
# homeassistant.components.agent_dvr
|
||||||
agent-py==0.0.23
|
agent-py==0.0.23
|
||||||
@ -141,7 +141,7 @@ aiohomekit==0.6.11
|
|||||||
aiohttp_cors==0.7.0
|
aiohttp_cors==0.7.0
|
||||||
|
|
||||||
# homeassistant.components.hue
|
# homeassistant.components.hue
|
||||||
aiohue==4.0.1
|
aiohue==4.1.2
|
||||||
|
|
||||||
# homeassistant.components.homewizard
|
# homeassistant.components.homewizard
|
||||||
aiohwenergy==0.8.0
|
aiohwenergy==0.8.0
|
||||||
@ -427,7 +427,7 @@ fjaraskupan==1.0.2
|
|||||||
flipr-api==1.4.1
|
flipr-api==1.4.1
|
||||||
|
|
||||||
# homeassistant.components.flux_led
|
# homeassistant.components.flux_led
|
||||||
flux_led==0.28.22
|
flux_led==0.28.26
|
||||||
|
|
||||||
# homeassistant.components.homekit
|
# homeassistant.components.homekit
|
||||||
fnvhash==0.1.0
|
fnvhash==0.1.0
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = homeassistant
|
name = homeassistant
|
||||||
version = 2022.2.6
|
version = 2022.2.7
|
||||||
author = The Home Assistant Authors
|
author = The Home Assistant Authors
|
||||||
author_email = hello@home-assistant.io
|
author_email = hello@home-assistant.io
|
||||||
license = Apache-2.0
|
license = Apache-2.0
|
||||||
|
@ -8,7 +8,6 @@ from unittest.mock import AsyncMock, Mock, patch
|
|||||||
import aiohue.v1 as aiohue_v1
|
import aiohue.v1 as aiohue_v1
|
||||||
import aiohue.v2 as aiohue_v2
|
import aiohue.v2 as aiohue_v2
|
||||||
from aiohue.v2.controllers.events import EventType
|
from aiohue.v2.controllers.events import EventType
|
||||||
from aiohue.v2.models.clip import parse_clip_resource
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import hue
|
from homeassistant.components import hue
|
||||||
@ -187,7 +186,7 @@ def create_mock_api_v2(hass):
|
|||||||
|
|
||||||
def emit_event(event_type, data):
|
def emit_event(event_type, data):
|
||||||
"""Emit an event from a (hue resource) dict."""
|
"""Emit an event from a (hue resource) dict."""
|
||||||
api.events.emit(EventType(event_type), parse_clip_resource(data))
|
api.events.emit(EventType(event_type), data)
|
||||||
|
|
||||||
api.load_test_data = load_test_data
|
api.load_test_data = load_test_data
|
||||||
api.emit_event = emit_event
|
api.emit_event = emit_event
|
||||||
|
@ -97,8 +97,12 @@ async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
|
|||||||
assert mock_bridge_v2.mock_requests[0]["json"]["color_temperature"]["mirek"] == 300
|
assert mock_bridge_v2.mock_requests[0]["json"]["color_temperature"]["mirek"] == 300
|
||||||
|
|
||||||
# Now generate update event by emitting the json we've sent as incoming event
|
# Now generate update event by emitting the json we've sent as incoming event
|
||||||
mock_bridge_v2.mock_requests[0]["json"]["color_temperature"].pop("mirek_valid")
|
event = {
|
||||||
mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"])
|
"id": "3a6710fa-4474-4eba-b533-5e6e72968feb",
|
||||||
|
"type": "light",
|
||||||
|
**mock_bridge_v2.mock_requests[0]["json"],
|
||||||
|
}
|
||||||
|
mock_bridge_v2.api.emit_event("update", event)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# the light should now be on
|
# the light should now be on
|
||||||
@ -186,7 +190,12 @@ async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_da
|
|||||||
assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False
|
assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False
|
||||||
|
|
||||||
# Now generate update event by emitting the json we've sent as incoming event
|
# Now generate update event by emitting the json we've sent as incoming event
|
||||||
mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"])
|
event = {
|
||||||
|
"id": "02cba059-9c2c-4d45-97e4-4f79b1bfbaa1",
|
||||||
|
"type": "light",
|
||||||
|
**mock_bridge_v2.mock_requests[0]["json"],
|
||||||
|
}
|
||||||
|
mock_bridge_v2.api.emit_event("update", event)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# the light should now be off
|
# the light should now be off
|
||||||
@ -377,10 +386,20 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Now generate update events by emitting the json we've sent as incoming events
|
# Now generate update events by emitting the json we've sent as incoming events
|
||||||
for index in range(0, 3):
|
for index, light_id in enumerate(
|
||||||
mock_bridge_v2.api.emit_event(
|
[
|
||||||
"update", mock_bridge_v2.mock_requests[index]["json"]
|
"02cba059-9c2c-4d45-97e4-4f79b1bfbaa1",
|
||||||
)
|
"b3fe71ef-d0ef-48de-9355-d9e604377df0",
|
||||||
|
"8015b17f-8336-415b-966a-b364bd082397",
|
||||||
|
]
|
||||||
|
):
|
||||||
|
event = {
|
||||||
|
"id": light_id,
|
||||||
|
"type": "light",
|
||||||
|
**mock_bridge_v2.mock_requests[index]["json"],
|
||||||
|
}
|
||||||
|
mock_bridge_v2.api.emit_event("update", event)
|
||||||
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# the light should now be on and have the properties we've set
|
# the light should now be on and have the properties we've set
|
||||||
@ -406,6 +425,12 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||||||
assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False
|
assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False
|
||||||
|
|
||||||
# Now generate update event by emitting the json we've sent as incoming event
|
# Now generate update event by emitting the json we've sent as incoming event
|
||||||
|
event = {
|
||||||
|
"id": "f2416154-9607-43ab-a684-4453108a200e",
|
||||||
|
"type": "grouped_light",
|
||||||
|
**mock_bridge_v2.mock_requests[0]["json"],
|
||||||
|
}
|
||||||
|
mock_bridge_v2.api.emit_event("update", event)
|
||||||
mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"])
|
mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"])
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -69,7 +69,12 @@ async def test_switch_turn_off_service(hass, mock_bridge_v2, v2_resources_test_d
|
|||||||
assert mock_bridge_v2.mock_requests[0]["json"]["enabled"] is False
|
assert mock_bridge_v2.mock_requests[0]["json"]["enabled"] is False
|
||||||
|
|
||||||
# Now generate update event by emitting the json we've sent as incoming event
|
# Now generate update event by emitting the json we've sent as incoming event
|
||||||
mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"])
|
event = {
|
||||||
|
"id": "b6896534-016d-4052-8cb4-ef04454df62c",
|
||||||
|
"type": "motion",
|
||||||
|
**mock_bridge_v2.mock_requests[0]["json"],
|
||||||
|
}
|
||||||
|
mock_bridge_v2.api.emit_event("update", event)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# the switch should now be off
|
# the switch should now be off
|
||||||
|
@ -62,7 +62,12 @@ async def test_services(hass):
|
|||||||
"source": "sensor.energy",
|
"source": "sensor.energy",
|
||||||
"cycle": "hourly",
|
"cycle": "hourly",
|
||||||
"tariffs": ["peak", "offpeak"],
|
"tariffs": ["peak", "offpeak"],
|
||||||
}
|
},
|
||||||
|
"energy_bill2": {
|
||||||
|
"source": "sensor.energy",
|
||||||
|
"cycle": "hourly",
|
||||||
|
"tariffs": ["peak", "offpeak"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +158,10 @@ async def test_services(hass):
|
|||||||
state = hass.states.get("sensor.energy_bill_offpeak")
|
state = hass.states.get("sensor.energy_bill_offpeak")
|
||||||
assert state.state == "0"
|
assert state.state == "0"
|
||||||
|
|
||||||
|
# meanwhile energy_bill2_peak accumulated all kWh
|
||||||
|
state = hass.states.get("sensor.energy_bill2_peak")
|
||||||
|
assert state.state == "4"
|
||||||
|
|
||||||
|
|
||||||
async def test_cron(hass, legacy_patchable_time):
|
async def test_cron(hass, legacy_patchable_time):
|
||||||
"""Test cron pattern and offset fails."""
|
"""Test cron pattern and offset fails."""
|
||||||
|
@ -304,6 +304,10 @@ async def test_restore_state(hass):
|
|||||||
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
|
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
State(
|
||||||
|
"sensor.energy_bill_midpeak",
|
||||||
|
"error",
|
||||||
|
),
|
||||||
State(
|
State(
|
||||||
"sensor.energy_bill_offpeak",
|
"sensor.energy_bill_offpeak",
|
||||||
"6",
|
"6",
|
||||||
@ -326,6 +330,9 @@ async def test_restore_state(hass):
|
|||||||
assert state.attributes.get("last_reset") == last_reset
|
assert state.attributes.get("last_reset") == last_reset
|
||||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR
|
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.energy_bill_midpeak")
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
state = hass.states.get("sensor.energy_bill_offpeak")
|
state = hass.states.get("sensor.energy_bill_offpeak")
|
||||||
assert state.state == "6"
|
assert state.state == "6"
|
||||||
assert state.attributes.get("status") == COLLECTING
|
assert state.attributes.get("status") == COLLECTING
|
||||||
@ -530,7 +537,7 @@ async def _test_self_reset(hass, config, start_time, expect_reset=True):
|
|||||||
assert state.attributes.get("last_reset") == now.isoformat()
|
assert state.attributes.get("last_reset") == now.isoformat()
|
||||||
assert state.state == "3"
|
assert state.state == "3"
|
||||||
else:
|
else:
|
||||||
assert state.attributes.get("last_period") == 0
|
assert state.attributes.get("last_period") == "0"
|
||||||
assert state.state == "5"
|
assert state.state == "5"
|
||||||
start_time_str = dt_util.parse_datetime(start_time).isoformat()
|
start_time_str = dt_util.parse_datetime(start_time).isoformat()
|
||||||
assert state.attributes.get("last_reset") == start_time_str
|
assert state.attributes.get("last_reset") == start_time_str
|
||||||
@ -559,7 +566,7 @@ async def _test_self_reset(hass, config, start_time, expect_reset=True):
|
|||||||
assert state.attributes.get("last_period") == "2"
|
assert state.attributes.get("last_period") == "2"
|
||||||
assert state.state == "7"
|
assert state.state == "7"
|
||||||
else:
|
else:
|
||||||
assert state.attributes.get("last_period") == 0
|
assert state.attributes.get("last_period") == "0"
|
||||||
assert state.state == "9"
|
assert state.state == "9"
|
||||||
|
|
||||||
|
|
||||||
|
@ -764,6 +764,5 @@ async def test_vizio_update_with_apps_on_input(
|
|||||||
)
|
)
|
||||||
await _add_config_entry_to_hass(hass, config_entry)
|
await _add_config_entry_to_hass(hass, config_entry)
|
||||||
attr = _get_attr_and_assert_base_attr(hass, DEVICE_CLASS_TV, STATE_ON)
|
attr = _get_attr_and_assert_base_attr(hass, DEVICE_CLASS_TV, STATE_ON)
|
||||||
# App name and app ID should not be in the attributes
|
# app ID should not be in the attributes
|
||||||
assert "app_name" not in attr
|
|
||||||
assert "app_id" not in attr
|
assert "app_id" not in attr
|
||||||
|
Loading…
x
Reference in New Issue
Block a user