mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Merge pull request #54249 from home-assistant/rc
This commit is contained in:
commit
f3de8b9f28
@ -91,13 +91,13 @@ class AdsCover(AdsEntity, CoverEntity):
|
|||||||
):
|
):
|
||||||
"""Initialize AdsCover entity."""
|
"""Initialize AdsCover entity."""
|
||||||
super().__init__(ads_hub, name, ads_var_is_closed)
|
super().__init__(ads_hub, name, ads_var_is_closed)
|
||||||
if self._ads_var is None:
|
if self._attr_unique_id is None:
|
||||||
if ads_var_position is not None:
|
if ads_var_position is not None:
|
||||||
self._unique_id = ads_var_position
|
self._attr_unique_id = ads_var_position
|
||||||
elif ads_var_pos_set is not None:
|
elif ads_var_pos_set is not None:
|
||||||
self._unique_id = ads_var_pos_set
|
self._attr_unique_id = ads_var_pos_set
|
||||||
elif ads_var_open is not None:
|
elif ads_var_open is not None:
|
||||||
self._unique_id = ads_var_open
|
self._attr_unique_id = ads_var_open
|
||||||
|
|
||||||
self._state_dict[STATE_KEY_POSITION] = None
|
self._state_dict[STATE_KEY_POSITION] = None
|
||||||
self._ads_var_position = ads_var_position
|
self._ads_var_position = ads_var_position
|
||||||
|
@ -49,7 +49,10 @@ def setup_platform(
|
|||||||
try:
|
try:
|
||||||
if not acc.login():
|
if not acc.login():
|
||||||
raise ValueError("Username or Password is incorrect")
|
raise ValueError("Username or Password is incorrect")
|
||||||
add_entities(AladdinDevice(acc, door) for door in acc.get_doors())
|
add_entities(
|
||||||
|
(AladdinDevice(acc, door) for door in acc.get_doors()),
|
||||||
|
update_before_add=True,
|
||||||
|
)
|
||||||
except (TypeError, KeyError, NameError, ValueError) as ex:
|
except (TypeError, KeyError, NameError, ValueError) as ex:
|
||||||
_LOGGER.error("%s", ex)
|
_LOGGER.error("%s", ex)
|
||||||
hass.components.persistent_notification.create(
|
hass.components.persistent_notification.create(
|
||||||
|
@ -449,6 +449,11 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
ATTR_HDMI_INPUT: None,
|
ATTR_HDMI_INPUT: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_image_hash(self):
|
||||||
|
"""Hash value for media image."""
|
||||||
|
return f"{datetime.now().timestamp()}" if self._screencap else None
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def _adb_screencap(self):
|
async def _adb_screencap(self):
|
||||||
"""Take a screen capture from the device."""
|
"""Take a screen capture from the device."""
|
||||||
@ -458,9 +463,6 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
"""Fetch current playing image."""
|
"""Fetch current playing image."""
|
||||||
if not self._screencap or self.state in [STATE_OFF, None] or not self.available:
|
if not self._screencap or self.state in [STATE_OFF, None] or not self.available:
|
||||||
return None, None
|
return None, None
|
||||||
self._attr_media_image_hash = (
|
|
||||||
f"{datetime.now().timestamp()}" if self._screencap else None
|
|
||||||
)
|
|
||||||
|
|
||||||
media_data = await self._adb_screencap()
|
media_data = await self._adb_screencap()
|
||||||
if media_data:
|
if media_data:
|
||||||
|
@ -223,7 +223,6 @@ SENSOR_TYPES = {
|
|||||||
None,
|
None,
|
||||||
4,
|
4,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
None,
|
|
||||||
],
|
],
|
||||||
"Flame": ["Flame", None, "mdi:toggle-switch", 2, None],
|
"Flame": ["Flame", None, "mdi:toggle-switch", 2, None],
|
||||||
"PowerEnergyConsumptionHeatingCircuit": [
|
"PowerEnergyConsumptionHeatingCircuit": [
|
||||||
|
@ -66,6 +66,7 @@ from .const import (
|
|||||||
CONF_INPUT_TYPE,
|
CONF_INPUT_TYPE,
|
||||||
CONF_MAX_TEMP,
|
CONF_MAX_TEMP,
|
||||||
CONF_MIN_TEMP,
|
CONF_MIN_TEMP,
|
||||||
|
CONF_MSG_WAIT,
|
||||||
CONF_PARITY,
|
CONF_PARITY,
|
||||||
CONF_PRECISION,
|
CONF_PRECISION,
|
||||||
CONF_RETRIES,
|
CONF_RETRIES,
|
||||||
@ -283,6 +284,7 @@ MODBUS_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(CONF_DELAY, default=0): cv.positive_int,
|
vol.Optional(CONF_DELAY, default=0): cv.positive_int,
|
||||||
vol.Optional(CONF_RETRIES, default=3): cv.positive_int,
|
vol.Optional(CONF_RETRIES, default=3): cv.positive_int,
|
||||||
vol.Optional(CONF_RETRY_ON_EMPTY, default=False): cv.boolean,
|
vol.Optional(CONF_RETRY_ON_EMPTY, default=False): cv.boolean,
|
||||||
|
vol.Optional(CONF_MSG_WAIT): cv.positive_int,
|
||||||
vol.Optional(CONF_BINARY_SENSORS): vol.All(
|
vol.Optional(CONF_BINARY_SENSORS): vol.All(
|
||||||
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
|
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
|
||||||
),
|
),
|
||||||
|
@ -31,6 +31,7 @@ CONF_INPUTS = "inputs"
|
|||||||
CONF_INPUT_TYPE = "input_type"
|
CONF_INPUT_TYPE = "input_type"
|
||||||
CONF_MAX_TEMP = "max_temp"
|
CONF_MAX_TEMP = "max_temp"
|
||||||
CONF_MIN_TEMP = "min_temp"
|
CONF_MIN_TEMP = "min_temp"
|
||||||
|
CONF_MSG_WAIT = "message_wait_milliseconds"
|
||||||
CONF_PARITY = "parity"
|
CONF_PARITY = "parity"
|
||||||
CONF_REGISTER = "register"
|
CONF_REGISTER = "register"
|
||||||
CONF_REGISTER_TYPE = "register_type"
|
CONF_REGISTER_TYPE = "register_type"
|
||||||
|
@ -39,6 +39,7 @@ from .const import (
|
|||||||
CONF_BAUDRATE,
|
CONF_BAUDRATE,
|
||||||
CONF_BYTESIZE,
|
CONF_BYTESIZE,
|
||||||
CONF_CLOSE_COMM_ON_ERROR,
|
CONF_CLOSE_COMM_ON_ERROR,
|
||||||
|
CONF_MSG_WAIT,
|
||||||
CONF_PARITY,
|
CONF_PARITY,
|
||||||
CONF_RETRIES,
|
CONF_RETRIES,
|
||||||
CONF_RETRY_ON_EMPTY,
|
CONF_RETRY_ON_EMPTY,
|
||||||
@ -229,6 +230,12 @@ class ModbusHub:
|
|||||||
self._pb_params["framer"] = ModbusRtuFramer
|
self._pb_params["framer"] = ModbusRtuFramer
|
||||||
|
|
||||||
Defaults.Timeout = client_config[CONF_TIMEOUT]
|
Defaults.Timeout = client_config[CONF_TIMEOUT]
|
||||||
|
if CONF_MSG_WAIT in client_config:
|
||||||
|
self._msg_wait = client_config[CONF_MSG_WAIT] / 1000
|
||||||
|
elif self._config_type == CONF_SERIAL:
|
||||||
|
self._msg_wait = 30 / 1000
|
||||||
|
else:
|
||||||
|
self._msg_wait = 0
|
||||||
|
|
||||||
def _log_error(self, text: str, error_state=True):
|
def _log_error(self, text: str, error_state=True):
|
||||||
log_text = f"Pymodbus: {text}"
|
log_text = f"Pymodbus: {text}"
|
||||||
@ -322,7 +329,7 @@ class ModbusHub:
|
|||||||
result = await self.hass.async_add_executor_job(
|
result = await self.hass.async_add_executor_job(
|
||||||
self._pymodbus_call, unit, address, value, use_call
|
self._pymodbus_call, unit, address, value, use_call
|
||||||
)
|
)
|
||||||
if self._config_type == "serial":
|
if self._msg_wait:
|
||||||
# small delay until next request/response
|
# small delay until next request/response
|
||||||
await asyncio.sleep(30 / 1000)
|
await asyncio.sleep(self._msg_wait)
|
||||||
return result
|
return result
|
||||||
|
@ -72,6 +72,7 @@ def struct_validator(config):
|
|||||||
_LOGGER.warning(error)
|
_LOGGER.warning(error)
|
||||||
try:
|
try:
|
||||||
data_type = OLD_DATA_TYPES[data_type][config.get(CONF_COUNT, 1)]
|
data_type = OLD_DATA_TYPES[data_type][config.get(CONF_COUNT, 1)]
|
||||||
|
config[CONF_DATA_TYPE] = data_type
|
||||||
except KeyError as exp:
|
except KeyError as exp:
|
||||||
error = f"{name} cannot convert automatically {data_type}"
|
error = f"{name} cannot convert automatically {data_type}"
|
||||||
raise vol.Invalid(error) from exp
|
raise vol.Invalid(error) from exp
|
||||||
|
@ -53,7 +53,7 @@ from homeassistant.helpers.dispatcher import (
|
|||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.entity import DeviceInfo, EntityDescription
|
from homeassistant.helpers.entity import DeviceInfo, EntityDescription
|
||||||
from homeassistant.helpers.network import get_url
|
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
@ -145,12 +145,21 @@ def listen_for_new_cameras(
|
|||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_generate_motioneye_webhook(hass: HomeAssistant, webhook_id: str) -> str:
|
def async_generate_motioneye_webhook(
|
||||||
|
hass: HomeAssistant, webhook_id: str
|
||||||
|
) -> str | None:
|
||||||
"""Generate the full local URL for a webhook_id."""
|
"""Generate the full local URL for a webhook_id."""
|
||||||
return "{}{}".format(
|
try:
|
||||||
get_url(hass, allow_cloud=False),
|
return "{}{}".format(
|
||||||
async_generate_path(webhook_id),
|
get_url(hass, allow_cloud=False),
|
||||||
)
|
async_generate_path(webhook_id),
|
||||||
|
)
|
||||||
|
except NoURLAvailableError:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Unable to get Home Assistant URL. Have you set the internal and/or "
|
||||||
|
"external URLs in Configuration -> General?"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -228,28 +237,31 @@ def _add_camera(
|
|||||||
if entry.options.get(CONF_WEBHOOK_SET, DEFAULT_WEBHOOK_SET):
|
if entry.options.get(CONF_WEBHOOK_SET, DEFAULT_WEBHOOK_SET):
|
||||||
url = async_generate_motioneye_webhook(hass, entry.data[CONF_WEBHOOK_ID])
|
url = async_generate_motioneye_webhook(hass, entry.data[CONF_WEBHOOK_ID])
|
||||||
|
|
||||||
if _set_webhook(
|
if url and (
|
||||||
_build_url(
|
_set_webhook(
|
||||||
device,
|
_build_url(
|
||||||
url,
|
device,
|
||||||
EVENT_MOTION_DETECTED,
|
url,
|
||||||
EVENT_MOTION_DETECTED_KEYS,
|
EVENT_MOTION_DETECTED,
|
||||||
),
|
EVENT_MOTION_DETECTED_KEYS,
|
||||||
KEY_WEB_HOOK_NOTIFICATIONS_URL,
|
),
|
||||||
KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD,
|
KEY_WEB_HOOK_NOTIFICATIONS_URL,
|
||||||
KEY_WEB_HOOK_NOTIFICATIONS_ENABLED,
|
KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD,
|
||||||
camera,
|
KEY_WEB_HOOK_NOTIFICATIONS_ENABLED,
|
||||||
) | _set_webhook(
|
camera,
|
||||||
_build_url(
|
)
|
||||||
device,
|
| _set_webhook(
|
||||||
url,
|
_build_url(
|
||||||
EVENT_FILE_STORED,
|
device,
|
||||||
EVENT_FILE_STORED_KEYS,
|
url,
|
||||||
),
|
EVENT_FILE_STORED,
|
||||||
KEY_WEB_HOOK_STORAGE_URL,
|
EVENT_FILE_STORED_KEYS,
|
||||||
KEY_WEB_HOOK_STORAGE_HTTP_METHOD,
|
),
|
||||||
KEY_WEB_HOOK_STORAGE_ENABLED,
|
KEY_WEB_HOOK_STORAGE_URL,
|
||||||
camera,
|
KEY_WEB_HOOK_STORAGE_HTTP_METHOD,
|
||||||
|
KEY_WEB_HOOK_STORAGE_ENABLED,
|
||||||
|
camera,
|
||||||
|
)
|
||||||
):
|
):
|
||||||
hass.async_create_task(client.async_set_camera(camera_id, camera))
|
hass.async_create_task(client.async_set_camera(camera_id, camera))
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ from .const import (
|
|||||||
DOMAIN,
|
DOMAIN,
|
||||||
KEY_COORDINATOR,
|
KEY_COORDINATOR,
|
||||||
KEY_DEVICE,
|
KEY_DEVICE,
|
||||||
|
MODEL_AIRHUMIDIFIER_CA1,
|
||||||
|
MODEL_AIRHUMIDIFIER_CB1,
|
||||||
MODELS_HUMIDIFIER_MIOT,
|
MODELS_HUMIDIFIER_MIOT,
|
||||||
)
|
)
|
||||||
from .device import XiaomiCoordinatedMiioEntity, XiaomiMiioEntity
|
from .device import XiaomiCoordinatedMiioEntity, XiaomiMiioEntity
|
||||||
@ -63,16 +65,17 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTR_POWER = "power"
|
ATTR_ACTUAL_SPEED = "actual_speed"
|
||||||
ATTR_CHARGING = "charging"
|
ATTR_CHARGING = "charging"
|
||||||
ATTR_DISPLAY_CLOCK = "display_clock"
|
ATTR_DISPLAY_CLOCK = "display_clock"
|
||||||
|
ATTR_HUMIDITY = "humidity"
|
||||||
|
ATTR_MOTOR_SPEED = "motor_speed"
|
||||||
ATTR_NIGHT_MODE = "night_mode"
|
ATTR_NIGHT_MODE = "night_mode"
|
||||||
ATTR_NIGHT_TIME_BEGIN = "night_time_begin"
|
ATTR_NIGHT_TIME_BEGIN = "night_time_begin"
|
||||||
ATTR_NIGHT_TIME_END = "night_time_end"
|
ATTR_NIGHT_TIME_END = "night_time_end"
|
||||||
|
ATTR_POWER = "power"
|
||||||
ATTR_SENSOR_STATE = "sensor_state"
|
ATTR_SENSOR_STATE = "sensor_state"
|
||||||
ATTR_WATER_LEVEL = "water_level"
|
ATTR_WATER_LEVEL = "water_level"
|
||||||
ATTR_HUMIDITY = "humidity"
|
|
||||||
ATTR_ACTUAL_MOTOR_SPEED = "actual_speed"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -121,6 +124,13 @@ SENSOR_TYPES = {
|
|||||||
valid_min_value=200.0,
|
valid_min_value=200.0,
|
||||||
valid_max_value=2000.0,
|
valid_max_value=2000.0,
|
||||||
),
|
),
|
||||||
|
"motor_speed": SensorType(
|
||||||
|
unit="rpm",
|
||||||
|
icon="mdi:fast-forward",
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
valid_min_value=200.0,
|
||||||
|
valid_max_value=2000.0,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
HUMIDIFIER_SENSORS = {
|
HUMIDIFIER_SENSORS = {
|
||||||
@ -128,11 +138,17 @@ HUMIDIFIER_SENSORS = {
|
|||||||
ATTR_TEMPERATURE: "temperature",
|
ATTR_TEMPERATURE: "temperature",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HUMIDIFIER_CA1_CB1_SENSORS = {
|
||||||
|
ATTR_HUMIDITY: "humidity",
|
||||||
|
ATTR_TEMPERATURE: "temperature",
|
||||||
|
ATTR_MOTOR_SPEED: "motor_speed",
|
||||||
|
}
|
||||||
|
|
||||||
HUMIDIFIER_SENSORS_MIOT = {
|
HUMIDIFIER_SENSORS_MIOT = {
|
||||||
ATTR_HUMIDITY: "humidity",
|
ATTR_HUMIDITY: "humidity",
|
||||||
ATTR_TEMPERATURE: "temperature",
|
ATTR_TEMPERATURE: "temperature",
|
||||||
ATTR_WATER_LEVEL: "water_level",
|
ATTR_WATER_LEVEL: "water_level",
|
||||||
ATTR_ACTUAL_MOTOR_SPEED: "actual_speed",
|
ATTR_ACTUAL_SPEED: "actual_speed",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -191,11 +207,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
sensors = []
|
sensors = []
|
||||||
if model in MODELS_HUMIDIFIER_MIOT:
|
if model in MODELS_HUMIDIFIER_MIOT:
|
||||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
|
|
||||||
sensors = HUMIDIFIER_SENSORS_MIOT
|
sensors = HUMIDIFIER_SENSORS_MIOT
|
||||||
|
elif model in (MODEL_AIRHUMIDIFIER_CA1, MODEL_AIRHUMIDIFIER_CB1):
|
||||||
|
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||||
|
sensors = HUMIDIFIER_CA1_CB1_SENSORS
|
||||||
elif model.startswith("zhimi.humidifier."):
|
elif model.startswith("zhimi.humidifier."):
|
||||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
|
|
||||||
sensors = HUMIDIFIER_SENSORS
|
sensors = HUMIDIFIER_SENSORS
|
||||||
else:
|
else:
|
||||||
unique_id = config_entry.unique_id
|
unique_id = config_entry.unique_id
|
||||||
|
@ -5,7 +5,7 @@ from typing import Final
|
|||||||
|
|
||||||
MAJOR_VERSION: Final = 2021
|
MAJOR_VERSION: Final = 2021
|
||||||
MINOR_VERSION: Final = 8
|
MINOR_VERSION: Final = 8
|
||||||
PATCH_VERSION: Final = "3"
|
PATCH_VERSION: Final = "4"
|
||||||
__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, 8, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||||
|
@ -51,6 +51,11 @@ httplib2>=0.19.0
|
|||||||
# https://github.com/home-assistant/core/issues/40148
|
# https://github.com/home-assistant/core/issues/40148
|
||||||
grpcio==1.31.0
|
grpcio==1.31.0
|
||||||
|
|
||||||
|
# Newer versions of cloud pubsub pin a higher version of grpcio. This can
|
||||||
|
# be reverted when the grpcio pin is reverted, see:
|
||||||
|
# https://github.com/home-assistant/core/issues/53427
|
||||||
|
google-cloud-pubsub==2.1.0
|
||||||
|
|
||||||
# This is a old unmaintained library and is replaced with pycryptodome
|
# This is a old unmaintained library and is replaced with pycryptodome
|
||||||
pycrypto==1000000000.0.0
|
pycrypto==1000000000.0.0
|
||||||
|
|
||||||
|
@ -73,6 +73,11 @@ httplib2>=0.19.0
|
|||||||
# https://github.com/home-assistant/core/issues/40148
|
# https://github.com/home-assistant/core/issues/40148
|
||||||
grpcio==1.31.0
|
grpcio==1.31.0
|
||||||
|
|
||||||
|
# Newer versions of cloud pubsub pin a higher version of grpcio. This can
|
||||||
|
# be reverted when the grpcio pin is reverted, see:
|
||||||
|
# https://github.com/home-assistant/core/issues/53427
|
||||||
|
google-cloud-pubsub==2.1.0
|
||||||
|
|
||||||
# This is a old unmaintained library and is replaced with pycryptodome
|
# This is a old unmaintained library and is replaced with pycryptodome
|
||||||
pycrypto==1000000000.0.0
|
pycrypto==1000000000.0.0
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ from homeassistant.components.modbus.const import (
|
|||||||
CONF_BYTESIZE,
|
CONF_BYTESIZE,
|
||||||
CONF_DATA_TYPE,
|
CONF_DATA_TYPE,
|
||||||
CONF_INPUT_TYPE,
|
CONF_INPUT_TYPE,
|
||||||
|
CONF_MSG_WAIT,
|
||||||
CONF_PARITY,
|
CONF_PARITY,
|
||||||
CONF_STOPBITS,
|
CONF_STOPBITS,
|
||||||
CONF_SWAP,
|
CONF_SWAP,
|
||||||
@ -245,6 +246,7 @@ async def test_exception_struct_validator(do_config):
|
|||||||
CONF_PORT: "usb01",
|
CONF_PORT: "usb01",
|
||||||
CONF_PARITY: "E",
|
CONF_PARITY: "E",
|
||||||
CONF_STOPBITS: 1,
|
CONF_STOPBITS: 1,
|
||||||
|
CONF_MSG_WAIT: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
CONF_TYPE: "serial",
|
CONF_TYPE: "serial",
|
||||||
|
@ -32,11 +32,13 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
from homeassistant.helpers.network import NoURLAvailableError
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
TEST_CAMERA,
|
TEST_CAMERA,
|
||||||
TEST_CAMERA_DEVICE_IDENTIFIER,
|
TEST_CAMERA_DEVICE_IDENTIFIER,
|
||||||
|
TEST_CAMERA_ENTITY_ID,
|
||||||
TEST_CAMERA_ID,
|
TEST_CAMERA_ID,
|
||||||
TEST_CAMERA_NAME,
|
TEST_CAMERA_NAME,
|
||||||
TEST_CAMERAS,
|
TEST_CAMERAS,
|
||||||
@ -251,6 +253,35 @@ async def test_setup_camera_with_correct_webhook(
|
|||||||
assert not client.async_set_camera.called
|
assert not client.async_set_camera.called
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_camera_with_no_home_assistant_urls(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
caplog: Any,
|
||||||
|
) -> None:
|
||||||
|
"""Verify setup works without Home Assistant internal/external URLs."""
|
||||||
|
|
||||||
|
client = create_mock_motioneye_client()
|
||||||
|
config_entry = create_mock_motioneye_config_entry(hass, data={CONF_URL: TEST_URL})
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.motioneye.get_url", side_effect=NoURLAvailableError
|
||||||
|
):
|
||||||
|
await setup_mock_motioneye_config_entry(
|
||||||
|
hass,
|
||||||
|
config_entry=config_entry,
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should log a warning ...
|
||||||
|
assert "Unable to get Home Assistant URL" in caplog.text
|
||||||
|
|
||||||
|
# ... should not set callbacks in the camera ...
|
||||||
|
assert not client.async_set_camera.called
|
||||||
|
|
||||||
|
# ... but camera should still be present.
|
||||||
|
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
|
||||||
|
assert entity_state
|
||||||
|
|
||||||
|
|
||||||
async def test_good_query(hass: HomeAssistant, aiohttp_client: Any) -> None:
|
async def test_good_query(hass: HomeAssistant, aiohttp_client: Any) -> None:
|
||||||
"""Test good callbacks."""
|
"""Test good callbacks."""
|
||||||
await async_setup_component(hass, "http", {"http": {}})
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user