mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
commit
27c6fe4376
@ -634,6 +634,7 @@ omit =
|
||||
homeassistant/components/mjpeg/camera.py
|
||||
homeassistant/components/mochad/*
|
||||
homeassistant/components/modbus/climate.py
|
||||
homeassistant/components/modbus/modbus.py
|
||||
homeassistant/components/modem_callerid/sensor.py
|
||||
homeassistant/components/motion_blinds/__init__.py
|
||||
homeassistant/components/motion_blinds/const.py
|
||||
|
@ -59,8 +59,8 @@ def setup(hass, config):
|
||||
for device in devices:
|
||||
_LOGGER.info(
|
||||
"Discovered Ecovacs device on account: %s with nickname %s",
|
||||
device["did"],
|
||||
device["nick"],
|
||||
device.get("did"),
|
||||
device.get("nick"),
|
||||
)
|
||||
vacbot = VacBot(
|
||||
ecovacs_api.uid,
|
||||
@ -77,7 +77,8 @@ def setup(hass, config):
|
||||
"""Shut down open connections to Ecovacs XMPP server."""
|
||||
for device in hass.data[ECOVACS_DEVICES]:
|
||||
_LOGGER.info(
|
||||
"Shutting down connection to Ecovacs device %s", device.vacuum["did"]
|
||||
"Shutting down connection to Ecovacs device %s",
|
||||
device.vacuum.get("did"),
|
||||
)
|
||||
device.disconnect()
|
||||
|
||||
|
@ -77,7 +77,7 @@ class EsphomeCamera(Camera, EsphomeBaseEntity):
|
||||
await self._image_cond.wait()
|
||||
if not self.available:
|
||||
return None
|
||||
return self._state.image[:]
|
||||
return self._state.data[:]
|
||||
|
||||
async def _async_camera_stream_image(self) -> bytes | None:
|
||||
"""Return a single camera image in a stream."""
|
||||
@ -88,7 +88,7 @@ class EsphomeCamera(Camera, EsphomeBaseEntity):
|
||||
await self._image_cond.wait()
|
||||
if not self.available:
|
||||
return None
|
||||
return self._state.image[:]
|
||||
return self._state.data[:]
|
||||
|
||||
async def handle_async_mjpeg_stream(self, request):
|
||||
"""Serve an HTTP MJPEG stream from the camera."""
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "ESPHome",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/esphome",
|
||||
"requirements": ["aioesphomeapi==4.0.1"],
|
||||
"requirements": ["aioesphomeapi==5.0.0"],
|
||||
"zeroconf": ["_esphomelib._tcp.local."],
|
||||
"codeowners": ["@OttoWinter", "@jesserockz"],
|
||||
"after_dependencies": ["zeroconf", "tag"],
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Support for the Forecast.Solar sensor service."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_IDENTIFIERS, ATTR_MANUFACTURER, ATTR_NAME
|
||||
@ -64,5 +66,7 @@ class ForecastSolarSensorEntity(CoordinatorEntity, SensorEntity):
|
||||
@property
|
||||
def state(self) -> StateType:
|
||||
"""Return the state of the sensor."""
|
||||
state: StateType = getattr(self.coordinator.data, self._sensor.key)
|
||||
state: StateType | datetime = getattr(self.coordinator.data, self._sensor.key)
|
||||
if isinstance(state, datetime):
|
||||
return state.isoformat()
|
||||
return state
|
||||
|
@ -195,12 +195,13 @@ class FritzBoxTools:
|
||||
"""Scan for new devices and return a list of found device ids."""
|
||||
_LOGGER.debug("Checking devices for FRITZ!Box router %s", self.host)
|
||||
|
||||
_default_consider_home = DEFAULT_CONSIDER_HOME.total_seconds()
|
||||
if self._options:
|
||||
consider_home = self._options.get(
|
||||
CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds()
|
||||
CONF_CONSIDER_HOME, _default_consider_home
|
||||
)
|
||||
else:
|
||||
consider_home = DEFAULT_CONSIDER_HOME
|
||||
consider_home = _default_consider_home
|
||||
|
||||
new_device = False
|
||||
for known_host in self._update_info():
|
||||
|
@ -66,9 +66,6 @@ class KNXFan(KnxEntity, FanEntity):
|
||||
# FanSpeedMode.STEP if max_step is set
|
||||
self._step_range: tuple[int, int] | None = (1, max_step) if max_step else None
|
||||
|
||||
self._attr_supported_features = SUPPORT_SET_SPEED
|
||||
if self._device.supports_oscillation:
|
||||
self._attr_supported_features |= SUPPORT_OSCILLATE
|
||||
self._attr_unique_id = str(self._device.speed.group_address)
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
@ -79,6 +76,16 @@ class KNXFan(KnxEntity, FanEntity):
|
||||
else:
|
||||
await self._device.set_speed(percentage)
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Flag supported features."""
|
||||
flags = SUPPORT_SET_SPEED
|
||||
|
||||
if self._device.supports_oscillation:
|
||||
flags |= SUPPORT_OSCILLATE
|
||||
|
||||
return flags
|
||||
|
||||
@property
|
||||
def percentage(self) -> int | None:
|
||||
"""Return the current speed as a percentage."""
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "lutron",
|
||||
"name": "Lutron",
|
||||
"documentation": "https://www.home-assistant.io/integrations/lutron",
|
||||
"requirements": ["pylutron==0.2.7"],
|
||||
"requirements": ["pylutron==0.2.8"],
|
||||
"codeowners": ["@JonGilmore"],
|
||||
"iot_class": "local_polling"
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ async def async_setup_entry(
|
||||
|
||||
def _build_forecast_data(timestep):
|
||||
data = {}
|
||||
data[ATTR_FORECAST_TIME] = timestep.date
|
||||
data[ATTR_FORECAST_TIME] = timestep.date.isoformat()
|
||||
if timestep.weather:
|
||||
data[ATTR_FORECAST_CONDITION] = _get_weather_condition(timestep.weather.value)
|
||||
if timestep.precipitation:
|
||||
|
@ -310,6 +310,8 @@ class ModbusHub:
|
||||
"""Convert async to sync pymodbus call."""
|
||||
if self._config_delay:
|
||||
return None
|
||||
if not self._client:
|
||||
return None
|
||||
if not self._client.is_socket_open():
|
||||
return None
|
||||
async with self._lock:
|
||||
|
@ -59,6 +59,9 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
vol.Optional(ATTR_UNLATCH, default=False): cv.boolean,
|
||||
},
|
||||
"lock_n_go",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
"set_continuous_mode",
|
||||
{
|
||||
vol.Required(ATTR_ENABLE): cv.boolean,
|
||||
|
@ -191,6 +191,8 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Get rain data from weather data."""
|
||||
if "all" in rain:
|
||||
return round(rain["all"], 2)
|
||||
if "3h" in rain:
|
||||
return round(rain["3h"], 2)
|
||||
if "1h" in rain:
|
||||
return round(rain["1h"], 2)
|
||||
return 0
|
||||
@ -201,6 +203,8 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||
if snow:
|
||||
if "all" in snow:
|
||||
return round(snow["all"], 2)
|
||||
if "3h" in snow:
|
||||
return round(snow["3h"], 2)
|
||||
if "1h" in snow:
|
||||
return round(snow["1h"], 2)
|
||||
return 0
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "SimpliSafe",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||
"requirements": ["simplisafe-python==11.0.0"],
|
||||
"requirements": ["simplisafe-python==11.0.1"],
|
||||
"codeowners": ["@bachya"],
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
||||
|
@ -52,14 +52,17 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
MP_DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_ADVERTISE_ADDR): cv.string,
|
||||
vol.Optional(CONF_INTERFACE_ADDR): cv.string,
|
||||
vol.Optional(CONF_HOSTS): vol.All(
|
||||
cv.ensure_list_csv, [cv.string]
|
||||
),
|
||||
}
|
||||
MP_DOMAIN: vol.All(
|
||||
cv.deprecated(CONF_INTERFACE_ADDR),
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_ADVERTISE_ADDR): cv.string,
|
||||
vol.Optional(CONF_INTERFACE_ADDR): cv.string,
|
||||
vol.Optional(CONF_HOSTS): vol.All(
|
||||
cv.ensure_list_csv, [cv.string]
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -126,6 +129,13 @@ async def async_setup_entry( # noqa: C901
|
||||
if advertise_addr:
|
||||
pysonos.config.EVENT_ADVERTISE_IP = advertise_addr
|
||||
|
||||
if deprecated_address := config.get(CONF_INTERFACE_ADDR):
|
||||
_LOGGER.warning(
|
||||
"'%s' is deprecated, enable %s in the Network integration (https://www.home-assistant.io/integrations/network/)",
|
||||
CONF_INTERFACE_ADDR,
|
||||
deprecated_address,
|
||||
)
|
||||
|
||||
async def _async_stop_event_listener(event: Event) -> None:
|
||||
await asyncio.gather(
|
||||
*[speaker.async_unsubscribe() for speaker in data.discovered.values()],
|
||||
|
@ -71,6 +71,7 @@ SUBSCRIPTION_SERVICES = [
|
||||
"zoneGroupTopology",
|
||||
]
|
||||
UNAVAILABLE_VALUES = {"", "NOT_IMPLEMENTED", None}
|
||||
UNUSED_DEVICE_KEYS = ["SPID", "TargetRoomName"]
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -407,6 +408,10 @@ class SonosSpeaker:
|
||||
"""Update device properties from an event."""
|
||||
if more_info := event.variables.get("more_info"):
|
||||
battery_dict = dict(x.split(":") for x in more_info.split(","))
|
||||
for unused in UNUSED_DEVICE_KEYS:
|
||||
battery_dict.pop(unused, None)
|
||||
if not battery_dict:
|
||||
return
|
||||
if "BattChg" not in battery_dict:
|
||||
_LOGGER.debug(
|
||||
"Unknown device properties update for %s (%s), please report an issue: '%s'",
|
||||
|
@ -43,7 +43,6 @@ from .const import (
|
||||
)
|
||||
from .core import PROVIDERS, IdleTimer, StreamOutput
|
||||
from .hls import async_setup_hls
|
||||
from .recorder import RecorderOutput
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -265,6 +264,10 @@ class Stream:
|
||||
) -> None:
|
||||
"""Make a .mp4 recording from a provided stream."""
|
||||
|
||||
# Keep import here so that we can import stream integration without installing reqs
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from .recorder import RecorderOutput
|
||||
|
||||
# Check for file access
|
||||
if not self.hass.config.is_allowed_path(video_path):
|
||||
raise HomeAssistantError(f"Can't write {video_path}, no access to path!")
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Belkin WeMo",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/wemo",
|
||||
"requirements": ["pywemo==0.6.3"],
|
||||
"requirements": ["pywemo==0.6.5"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "Belkin International Inc."
|
||||
|
@ -5,7 +5,7 @@ from typing import Final
|
||||
|
||||
MAJOR_VERSION: Final = 2021
|
||||
MINOR_VERSION: Final = 7
|
||||
PATCH_VERSION: Final = "0"
|
||||
PATCH_VERSION: Final = "1"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||
|
@ -160,7 +160,7 @@ aioeafm==0.1.2
|
||||
aioemonitor==1.0.5
|
||||
|
||||
# homeassistant.components.esphome
|
||||
aioesphomeapi==4.0.1
|
||||
aioesphomeapi==5.0.0
|
||||
|
||||
# homeassistant.components.flo
|
||||
aioflo==0.4.1
|
||||
@ -1562,7 +1562,7 @@ pyloopenergy==0.2.1
|
||||
pylutron-caseta==0.10.0
|
||||
|
||||
# homeassistant.components.lutron
|
||||
pylutron==0.2.7
|
||||
pylutron==0.2.8
|
||||
|
||||
# homeassistant.components.mailgun
|
||||
pymailgunner==1.4
|
||||
@ -1966,7 +1966,7 @@ pyvolumio==0.1.3
|
||||
pywebpush==1.9.2
|
||||
|
||||
# homeassistant.components.wemo
|
||||
pywemo==0.6.3
|
||||
pywemo==0.6.5
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.70
|
||||
@ -2102,7 +2102,7 @@ simplehound==0.3
|
||||
simplepush==1.1.4
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==11.0.0
|
||||
simplisafe-python==11.0.1
|
||||
|
||||
# homeassistant.components.sisyphus
|
||||
sisyphus-control==3.0
|
||||
|
@ -100,7 +100,7 @@ aioeafm==0.1.2
|
||||
aioemonitor==1.0.5
|
||||
|
||||
# homeassistant.components.esphome
|
||||
aioesphomeapi==4.0.1
|
||||
aioesphomeapi==5.0.0
|
||||
|
||||
# homeassistant.components.flo
|
||||
aioflo==0.4.1
|
||||
@ -1084,7 +1084,7 @@ pyvolumio==0.1.3
|
||||
pywebpush==1.9.2
|
||||
|
||||
# homeassistant.components.wemo
|
||||
pywemo==0.6.3
|
||||
pywemo==0.6.5
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.70
|
||||
@ -1148,7 +1148,7 @@ sharkiqpy==0.1.8
|
||||
simplehound==0.3
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==11.0.0
|
||||
simplisafe-python==11.0.1
|
||||
|
||||
# homeassistant.components.slack
|
||||
slackclient==2.5.0
|
||||
|
@ -70,7 +70,7 @@ async def test_sensors(
|
||||
assert entry
|
||||
assert state
|
||||
assert entry.unique_id == f"{entry_id}_power_highest_peak_time_today"
|
||||
assert state.state == "2021-06-27 13:00:00+00:00"
|
||||
assert state.state == "2021-06-27T13:00:00+00:00"
|
||||
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Highest Power Peak Time - Today"
|
||||
assert state.attributes.get(ATTR_STATE_CLASS) is None
|
||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP
|
||||
@ -82,7 +82,7 @@ async def test_sensors(
|
||||
assert entry
|
||||
assert state
|
||||
assert entry.unique_id == f"{entry_id}_power_highest_peak_time_tomorrow"
|
||||
assert state.state == "2021-06-27 14:00:00+00:00"
|
||||
assert state.state == "2021-06-27T14:00:00+00:00"
|
||||
assert (
|
||||
state.attributes.get(ATTR_FRIENDLY_NAME) == "Highest Power Peak Time - Tomorrow"
|
||||
)
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
|
||||
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S%z"
|
||||
TEST_DATETIME_STRING = "2020-04-25 12:00:00+0000"
|
||||
TEST_DATETIME_STRING = "2020-04-25T12:00:00+00:00"
|
||||
|
||||
TEST_API_KEY = "test-metoffice-api-key"
|
||||
|
||||
|
@ -6,7 +6,6 @@ from homeassistant.components.metoffice.const import ATTRIBUTION, DOMAIN
|
||||
|
||||
from . import NewDateTime
|
||||
from .const import (
|
||||
DATETIME_FORMAT,
|
||||
KINGSLYNN_SENSOR_RESULTS,
|
||||
METOFFICE_CONFIG_KINGSLYNN,
|
||||
METOFFICE_CONFIG_WAVERTREE,
|
||||
@ -54,13 +53,10 @@ async def test_one_sensor_site_running(hass, requests_mock, legacy_patchable_tim
|
||||
for running_id in running_sensor_ids:
|
||||
sensor = hass.states.get(running_id)
|
||||
sensor_id = sensor.attributes.get("sensor_id")
|
||||
sensor_name, sensor_value = WAVERTREE_SENSOR_RESULTS[sensor_id]
|
||||
_, sensor_value = WAVERTREE_SENSOR_RESULTS[sensor_id]
|
||||
|
||||
assert sensor.state == sensor_value
|
||||
assert (
|
||||
sensor.attributes.get("last_update").strftime(DATETIME_FORMAT)
|
||||
== TEST_DATETIME_STRING
|
||||
)
|
||||
assert sensor.attributes.get("last_update").isoformat() == TEST_DATETIME_STRING
|
||||
assert sensor.attributes.get("site_id") == "354107"
|
||||
assert sensor.attributes.get("site_name") == TEST_SITE_NAME_WAVERTREE
|
||||
assert sensor.attributes.get("attribution") == ATTRIBUTION
|
||||
@ -115,11 +111,10 @@ async def test_two_sensor_sites_running(hass, requests_mock, legacy_patchable_ti
|
||||
sensor = hass.states.get(running_id)
|
||||
sensor_id = sensor.attributes.get("sensor_id")
|
||||
if sensor.attributes.get("site_id") == "354107":
|
||||
sensor_name, sensor_value = WAVERTREE_SENSOR_RESULTS[sensor_id]
|
||||
_, sensor_value = WAVERTREE_SENSOR_RESULTS[sensor_id]
|
||||
assert sensor.state == sensor_value
|
||||
assert (
|
||||
sensor.attributes.get("last_update").strftime(DATETIME_FORMAT)
|
||||
== TEST_DATETIME_STRING
|
||||
sensor.attributes.get("last_update").isoformat() == TEST_DATETIME_STRING
|
||||
)
|
||||
assert sensor.attributes.get("sensor_id") == sensor_id
|
||||
assert sensor.attributes.get("site_id") == "354107"
|
||||
@ -127,11 +122,10 @@ async def test_two_sensor_sites_running(hass, requests_mock, legacy_patchable_ti
|
||||
assert sensor.attributes.get("attribution") == ATTRIBUTION
|
||||
|
||||
else:
|
||||
sensor_name, sensor_value = KINGSLYNN_SENSOR_RESULTS[sensor_id]
|
||||
_, sensor_value = KINGSLYNN_SENSOR_RESULTS[sensor_id]
|
||||
assert sensor.state == sensor_value
|
||||
assert (
|
||||
sensor.attributes.get("last_update").strftime(DATETIME_FORMAT)
|
||||
== TEST_DATETIME_STRING
|
||||
sensor.attributes.get("last_update").isoformat() == TEST_DATETIME_STRING
|
||||
)
|
||||
assert sensor.attributes.get("sensor_id") == sensor_id
|
||||
assert sensor.attributes.get("site_id") == "322380"
|
||||
|
@ -9,7 +9,6 @@ from homeassistant.util import utcnow
|
||||
|
||||
from . import NewDateTime
|
||||
from .const import (
|
||||
DATETIME_FORMAT,
|
||||
METOFFICE_CONFIG_KINGSLYNN,
|
||||
METOFFICE_CONFIG_WAVERTREE,
|
||||
WAVERTREE_SENSOR_RESULTS,
|
||||
@ -74,11 +73,11 @@ async def test_site_cannot_update(hass, requests_mock, legacy_patchable_time):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert weather
|
||||
|
||||
entity = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert weather
|
||||
|
||||
requests_mock.get("/public/data/val/wxfcs/all/json/354107?res=3hourly", text="")
|
||||
requests_mock.get("/public/data/val/wxfcs/all/json/354107?res=daily", text="")
|
||||
@ -87,11 +86,11 @@ async def test_site_cannot_update(hass, requests_mock, legacy_patchable_time):
|
||||
async_fire_time_changed(hass, future_time)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert entity.state == STATE_UNAVAILABLE
|
||||
weather = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert weather.state == STATE_UNAVAILABLE
|
||||
|
||||
entity = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert entity.state == STATE_UNAVAILABLE
|
||||
weather = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert weather.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
@patch(
|
||||
@ -126,50 +125,49 @@ async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_ti
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Wavertree 3-hourly weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "sunny"
|
||||
assert entity.attributes.get("temperature") == 17
|
||||
assert entity.attributes.get("wind_speed") == 9
|
||||
assert entity.attributes.get("wind_bearing") == "SSE"
|
||||
assert entity.attributes.get("visibility") == "Good - 10-20"
|
||||
assert entity.attributes.get("humidity") == 50
|
||||
assert weather.state == "sunny"
|
||||
assert weather.attributes.get("temperature") == 17
|
||||
assert weather.attributes.get("wind_speed") == 9
|
||||
assert weather.attributes.get("wind_bearing") == "SSE"
|
||||
assert weather.attributes.get("visibility") == "Good - 10-20"
|
||||
assert weather.attributes.get("humidity") == 50
|
||||
|
||||
# Forecasts added - just pick out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 35
|
||||
assert len(weather.attributes.get("forecast")) == 35
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[26]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-28 21:00:00+0000"
|
||||
weather.attributes.get("forecast")[26]["datetime"]
|
||||
== "2020-04-28T21:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[26]["condition"] == "cloudy"
|
||||
assert entity.attributes.get("forecast")[26]["temperature"] == 10
|
||||
assert entity.attributes.get("forecast")[26]["wind_speed"] == 4
|
||||
assert entity.attributes.get("forecast")[26]["wind_bearing"] == "NNE"
|
||||
assert weather.attributes.get("forecast")[26]["condition"] == "cloudy"
|
||||
assert weather.attributes.get("forecast")[26]["temperature"] == 10
|
||||
assert weather.attributes.get("forecast")[26]["wind_speed"] == 4
|
||||
assert weather.attributes.get("forecast")[26]["wind_bearing"] == "NNE"
|
||||
|
||||
# Wavertree daily weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "sunny"
|
||||
assert entity.attributes.get("temperature") == 19
|
||||
assert entity.attributes.get("wind_speed") == 9
|
||||
assert entity.attributes.get("wind_bearing") == "SSE"
|
||||
assert entity.attributes.get("visibility") == "Good - 10-20"
|
||||
assert entity.attributes.get("humidity") == 50
|
||||
assert weather.state == "sunny"
|
||||
assert weather.attributes.get("temperature") == 19
|
||||
assert weather.attributes.get("wind_speed") == 9
|
||||
assert weather.attributes.get("wind_bearing") == "SSE"
|
||||
assert weather.attributes.get("visibility") == "Good - 10-20"
|
||||
assert weather.attributes.get("humidity") == 50
|
||||
|
||||
# Also has Forecasts added - again, just pick out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 8
|
||||
assert len(weather.attributes.get("forecast")) == 8
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[7]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-29 12:00:00+0000"
|
||||
weather.attributes.get("forecast")[7]["datetime"] == "2020-04-29T12:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[7]["condition"] == "rainy"
|
||||
assert entity.attributes.get("forecast")[7]["temperature"] == 13
|
||||
assert entity.attributes.get("forecast")[7]["wind_speed"] == 13
|
||||
assert entity.attributes.get("forecast")[7]["wind_bearing"] == "SE"
|
||||
assert weather.attributes.get("forecast")[7]["condition"] == "rainy"
|
||||
assert weather.attributes.get("forecast")[7]["temperature"] == 13
|
||||
assert weather.attributes.get("forecast")[7]["wind_speed"] == 13
|
||||
assert weather.attributes.get("forecast")[7]["wind_bearing"] == "SE"
|
||||
|
||||
|
||||
@patch(
|
||||
@ -216,93 +214,91 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Wavertree 3-hourly weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_3_hourly")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "sunny"
|
||||
assert entity.attributes.get("temperature") == 17
|
||||
assert entity.attributes.get("wind_speed") == 9
|
||||
assert entity.attributes.get("wind_bearing") == "SSE"
|
||||
assert entity.attributes.get("visibility") == "Good - 10-20"
|
||||
assert entity.attributes.get("humidity") == 50
|
||||
assert weather.state == "sunny"
|
||||
assert weather.attributes.get("temperature") == 17
|
||||
assert weather.attributes.get("wind_speed") == 9
|
||||
assert weather.attributes.get("wind_bearing") == "SSE"
|
||||
assert weather.attributes.get("visibility") == "Good - 10-20"
|
||||
assert weather.attributes.get("humidity") == 50
|
||||
|
||||
# Forecasts added - just pick out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 35
|
||||
assert len(weather.attributes.get("forecast")) == 35
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[18]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-27 21:00:00+0000"
|
||||
weather.attributes.get("forecast")[18]["datetime"]
|
||||
== "2020-04-27T21:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[18]["condition"] == "sunny"
|
||||
assert entity.attributes.get("forecast")[18]["temperature"] == 9
|
||||
assert entity.attributes.get("forecast")[18]["wind_speed"] == 4
|
||||
assert entity.attributes.get("forecast")[18]["wind_bearing"] == "NW"
|
||||
assert weather.attributes.get("forecast")[18]["condition"] == "sunny"
|
||||
assert weather.attributes.get("forecast")[18]["temperature"] == 9
|
||||
assert weather.attributes.get("forecast")[18]["wind_speed"] == 4
|
||||
assert weather.attributes.get("forecast")[18]["wind_bearing"] == "NW"
|
||||
|
||||
# Wavertree daily weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_wavertree_daily")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "sunny"
|
||||
assert entity.attributes.get("temperature") == 19
|
||||
assert entity.attributes.get("wind_speed") == 9
|
||||
assert entity.attributes.get("wind_bearing") == "SSE"
|
||||
assert entity.attributes.get("visibility") == "Good - 10-20"
|
||||
assert entity.attributes.get("humidity") == 50
|
||||
assert weather.state == "sunny"
|
||||
assert weather.attributes.get("temperature") == 19
|
||||
assert weather.attributes.get("wind_speed") == 9
|
||||
assert weather.attributes.get("wind_bearing") == "SSE"
|
||||
assert weather.attributes.get("visibility") == "Good - 10-20"
|
||||
assert weather.attributes.get("humidity") == 50
|
||||
|
||||
# Also has Forecasts added - again, just pick out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 8
|
||||
assert len(weather.attributes.get("forecast")) == 8
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[7]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-29 12:00:00+0000"
|
||||
weather.attributes.get("forecast")[7]["datetime"] == "2020-04-29T12:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[7]["condition"] == "rainy"
|
||||
assert entity.attributes.get("forecast")[7]["temperature"] == 13
|
||||
assert entity.attributes.get("forecast")[7]["wind_speed"] == 13
|
||||
assert entity.attributes.get("forecast")[7]["wind_bearing"] == "SE"
|
||||
assert weather.attributes.get("forecast")[7]["condition"] == "rainy"
|
||||
assert weather.attributes.get("forecast")[7]["temperature"] == 13
|
||||
assert weather.attributes.get("forecast")[7]["wind_speed"] == 13
|
||||
assert weather.attributes.get("forecast")[7]["wind_bearing"] == "SE"
|
||||
|
||||
# King's Lynn 3-hourly weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_king_s_lynn_3_hourly")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_king_s_lynn_3_hourly")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "sunny"
|
||||
assert entity.attributes.get("temperature") == 14
|
||||
assert entity.attributes.get("wind_speed") == 2
|
||||
assert entity.attributes.get("wind_bearing") == "E"
|
||||
assert entity.attributes.get("visibility") == "Very Good - 20-40"
|
||||
assert entity.attributes.get("humidity") == 60
|
||||
assert weather.state == "sunny"
|
||||
assert weather.attributes.get("temperature") == 14
|
||||
assert weather.attributes.get("wind_speed") == 2
|
||||
assert weather.attributes.get("wind_bearing") == "E"
|
||||
assert weather.attributes.get("visibility") == "Very Good - 20-40"
|
||||
assert weather.attributes.get("humidity") == 60
|
||||
|
||||
# Also has Forecast added - just pick out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 35
|
||||
assert len(weather.attributes.get("forecast")) == 35
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[18]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-27 21:00:00+0000"
|
||||
weather.attributes.get("forecast")[18]["datetime"]
|
||||
== "2020-04-27T21:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[18]["condition"] == "cloudy"
|
||||
assert entity.attributes.get("forecast")[18]["temperature"] == 10
|
||||
assert entity.attributes.get("forecast")[18]["wind_speed"] == 7
|
||||
assert entity.attributes.get("forecast")[18]["wind_bearing"] == "SE"
|
||||
assert weather.attributes.get("forecast")[18]["condition"] == "cloudy"
|
||||
assert weather.attributes.get("forecast")[18]["temperature"] == 10
|
||||
assert weather.attributes.get("forecast")[18]["wind_speed"] == 7
|
||||
assert weather.attributes.get("forecast")[18]["wind_bearing"] == "SE"
|
||||
|
||||
# King's Lynn daily weather platform expected results
|
||||
entity = hass.states.get("weather.met_office_king_s_lynn_daily")
|
||||
assert entity
|
||||
weather = hass.states.get("weather.met_office_king_s_lynn_daily")
|
||||
assert weather
|
||||
|
||||
assert entity.state == "cloudy"
|
||||
assert entity.attributes.get("temperature") == 9
|
||||
assert entity.attributes.get("wind_speed") == 4
|
||||
assert entity.attributes.get("wind_bearing") == "ESE"
|
||||
assert entity.attributes.get("visibility") == "Very Good - 20-40"
|
||||
assert entity.attributes.get("humidity") == 75
|
||||
assert weather.state == "cloudy"
|
||||
assert weather.attributes.get("temperature") == 9
|
||||
assert weather.attributes.get("wind_speed") == 4
|
||||
assert weather.attributes.get("wind_bearing") == "ESE"
|
||||
assert weather.attributes.get("visibility") == "Very Good - 20-40"
|
||||
assert weather.attributes.get("humidity") == 75
|
||||
|
||||
# All should have Forecast added - again, just picking out 1 entry to check
|
||||
assert len(entity.attributes.get("forecast")) == 8
|
||||
assert len(weather.attributes.get("forecast")) == 8
|
||||
|
||||
assert (
|
||||
entity.attributes.get("forecast")[5]["datetime"].strftime(DATETIME_FORMAT)
|
||||
== "2020-04-28 12:00:00+0000"
|
||||
weather.attributes.get("forecast")[5]["datetime"] == "2020-04-28T12:00:00+00:00"
|
||||
)
|
||||
assert entity.attributes.get("forecast")[5]["condition"] == "cloudy"
|
||||
assert entity.attributes.get("forecast")[5]["temperature"] == 11
|
||||
assert entity.attributes.get("forecast")[5]["wind_speed"] == 7
|
||||
assert entity.attributes.get("forecast")[5]["wind_bearing"] == "ESE"
|
||||
assert weather.attributes.get("forecast")[5]["condition"] == "cloudy"
|
||||
assert weather.attributes.get("forecast")[5]["temperature"] == 11
|
||||
assert weather.attributes.get("forecast")[5]["wind_speed"] == 7
|
||||
assert weather.attributes.get("forecast")[5]["wind_bearing"] == "ESE"
|
||||
|
@ -103,3 +103,23 @@ async def test_device_payload_without_battery(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert bad_payload in caplog.text
|
||||
|
||||
|
||||
async def test_device_payload_without_battery_and_ignored_keys(
|
||||
hass, config_entry, config, soco, battery_event, caplog
|
||||
):
|
||||
"""Test device properties event update without battery info and ignored keys."""
|
||||
soco.get_battery_info.return_value = None
|
||||
|
||||
await setup_platform(hass, config_entry, config)
|
||||
|
||||
subscription = soco.deviceProperties.subscribe.return_value
|
||||
sub_callback = subscription.callback
|
||||
|
||||
ignored_payload = "SPID:InCeiling,TargetRoomName:Bouncy House"
|
||||
battery_event.variables["more_info"] = ignored_payload
|
||||
|
||||
sub_callback(battery_event)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert ignored_payload not in caplog.text
|
||||
|
Loading…
x
Reference in New Issue
Block a user