Compare commits

..

44 Commits

Author SHA1 Message Date
Paulus Schoutsen
5080246fb6 Merge pull request #74760 from home-assistant/rc 2022-07-08 16:08:11 -07:00
Shay Levy
a3abe7456e Fix CI failure due to integrations leaving dirty known_devices.yaml (#74329) 2022-07-08 14:29:24 -07:00
Paulus Schoutsen
14c6b8d41f Bumped version to 2022.7.2 2022-07-08 14:22:45 -07:00
Benoit Anastay
ea709912d4 Fix error with HDD temperature report in Freebox integration (#74718)
* Fix error whith HDD temperature report

There was a non handled error case, documented in issue https://github.com/home-assistant/core/issues/43812 back in 2020 and the fix wasn't applied

* Use get method instead of ignoring the sensor

* Update test values

Add idle state drive with unkown temp

* update Tests for system sensors api

* Fix booleans values

* Fix disk unique_id

There was a typo in the code
2022-07-08 14:22:39 -07:00
Aaron Bach
cb5658d7dc Bump regenmaschine to 2022.07.0 (#74680) 2022-07-08 14:22:38 -07:00
Paulus Schoutsen
7b1cad223d Bump atomicwrites (#74758) 2022-07-08 14:18:19 -07:00
Robert Svensson
e80fd4fc78 Bump deconz dependency to fix #74523 (#74710) 2022-07-08 14:18:18 -07:00
TheJulianJES
88d723736f Fix ZHA group not setting the correct color mode (#74687)
* Fix ZHA group not setting the correct color mode

* Changed to use _attr_color_mode
2022-07-08 14:18:18 -07:00
siyuan-nz
dc33d5db82 Add ssh-rsa as acceptable an host key algorithm (#74684) 2022-07-08 14:18:17 -07:00
Kevin Stillhammer
7ffc60fb2c Add missing strings for here_travel_time (#74641)
* Add missing strings for here_travel_time

* script.translations develop

* Correct origin_menu option
2022-07-08 14:18:16 -07:00
Paulus Schoutsen
d539acf2ff Merge pull request #74689 from home-assistant/rc 2022-07-07 23:11:02 -07:00
Paulus Schoutsen
5018b91f6c Bumped version to 2022.7.1 2022-07-07 21:59:59 -07:00
Michał Mrozek
b73cc32ffb Update kaiterra-async-client to 1.0.0 (#74677) 2022-07-07 21:59:54 -07:00
J. Nick Koston
937d0d731d Fix exception in doorbird logbook during startup (#74649)
* Fix exception in doorbird logbook during startup

Fixes

```
2022-07-07 16:50:33.203 ERROR (MainThread) [homeassistant.helpers.integration_platform] Error processing platform doorbird.logbook
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/integration_platform.py", line 51, in _async_process_single_integration_platform_component
    await integration_platform.process_platform(hass, component_name, platform)
  File "/usr/src/homeassistant/homeassistant/components/logbook/__init__.py", line 159, in _process_logbook_platform
    platform.async_describe_events(hass, _async_describe_event)
  File "/usr/src/homeassistant/homeassistant/components/doorbird/logbook.py", line 43, in async_describe_events
    door_station = data[DOOR_STATION]
KeyError: door_station
```

* py39
2022-07-07 21:59:53 -07:00
TheJulianJES
bac9af50df Fix smart energy polling for Tuya plugs (#74640)
* Add PolledSmartEnergySummation to poll summation_delivered for some ZHA plugs

* Remove PolledSmartEnergyMetering, add stop_on_match_group to summation sensors
2022-07-07 21:59:52 -07:00
Franck Nijhof
0da09ba47e Fix mix of aiohttp and requests in ZAMG (#74628) 2022-07-07 21:59:51 -07:00
Bram Kragten
cd7f2eb73e Update frontend to 20220707.0 (#74625) 2022-07-07 21:59:51 -07:00
Arne Mauer
8b01c132c1 Ikea Starkvind support all models (#74615)
* Add Particulate Matter 2.5 of ZCL concentration clusters to ZHA component

* Fixed black and flake8 test

* New sensors and manufacturer cluster to support IKEA STARKVIND (with quirk)

* Fix multi_match for FilterLifeTime, device_run_time, filter_run_time sensors for Ikea starkvind

* Remove model match because sensors are matched with manufacturer channel

* Update manufacturerspecific.py

* Update number.py
2022-07-07 21:59:50 -07:00
Erik Montnemery
ed6a65156c Poll cast groups when media player is added or reconnected (#74610) 2022-07-07 21:59:49 -07:00
Franck Nijhof
5a7e506c38 Update aiokafka to 0.7.2 (#74601) 2022-07-07 21:59:48 -07:00
Franck Nijhof
9514b0f100 Fix mix of aiohttp and requests in Bloomsky (#74598) 2022-07-07 21:59:48 -07:00
Erik Montnemery
fdc1b6ea9e Fix openweathermap hourly forecast (#74578) 2022-07-07 21:59:47 -07:00
Glenn Waters
174837dddf ElkM1 bump lib to support Python 3.10 SSL (#74569)
Co-authored-by: J. Nick Koston <nick@koston.org>
2022-07-07 21:59:46 -07:00
ufodone
c9a31aab15 Bump pyenvisalink version to 4.6 (#74561) 2022-07-07 21:59:45 -07:00
Robert Hillis
606a1b57e6 Bump aioskybell to 22.7.0 (#74559) 2022-07-07 21:59:45 -07:00
jjlawren
f6a23492fa Minimize Sonos media_player.unjoin timeout (#74549) 2022-07-07 21:59:44 -07:00
Joakim Plate
414ea6fd8c fjaraskupan: Make sure we stop bleak on home assistant stop (#74545)
* Make sure we stop bleak on home assistant stop

* Fix typing

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2022-07-07 21:59:43 -07:00
c-soft
fa220c5c25 Bump satel_integra to 0.3.7 to fix compat with python 3.10 (#74543) 2022-07-07 21:59:43 -07:00
Robert Svensson
bf5633fa43 Bump deCONZ dependency to v96 (#74460) 2022-07-07 21:59:42 -07:00
Franck Nijhof
eb0f8f9542 Merge pull request #74522 from home-assistant/rc 2022-07-06 20:32:56 +02:00
Franck Nijhof
06c6ddb2d6 Bumped version to 2022.7.0 2022-07-06 19:33:46 +02:00
Franck Nijhof
8e5b6ff185 Update Home Assistant Frontend to 20220706.0 (#74520)
Bump Home Assistant Frontend to 20220706.0
2022-07-06 19:33:27 +02:00
Franck Nijhof
380244fa7b Update homematicip to 1.0.3 (#74516) 2022-07-06 19:33:23 +02:00
Erik Montnemery
9d3dde60ff Fix openweathermap forecast sensors (#74513) 2022-07-06 19:33:20 +02:00
Gyosa3
519d15428c Add new alias for valid Celcius temperature units in Tuya (#74511) 2022-07-06 19:33:17 +02:00
Marcel van der Veldt
b277c28ed7 Bump aioslimproto to 2.1.1 (#74499) 2022-07-06 19:33:14 +02:00
Erik Montnemery
c7c8887719 Migrate aemet weather to native_* (#74494) 2022-07-06 19:33:10 +02:00
J. Nick Koston
06aa92b0b6 Bump aiohomekit to 0.7.20 (#74489) 2022-07-06 19:33:07 +02:00
J. Nick Koston
cd42555238 Fix apple tv not coming online if connected before entity created (#74488) 2022-07-06 19:33:03 +02:00
Paulus Schoutsen
56e90dd30b Bumped version to 2022.7.0b5 2022-07-05 13:56:38 -07:00
Erik Montnemery
89360516d7 Revert "Migrate aemet to native_*" (#74471) 2022-07-05 13:56:34 -07:00
Zack Barett
9cbb684d50 Bump Frontend to 20220705.0 (#74467) 2022-07-05 13:56:33 -07:00
J. Nick Koston
43fe351f1b Avoid loading mqtt for type checking (#74464) 2022-07-05 13:56:32 -07:00
J. Nick Koston
59aba0bc75 Bump aiohomekit to 0.7.19 (#74463) 2022-07-05 13:56:32 -07:00
56 changed files with 478 additions and 344 deletions

View File

@@ -1,30 +1,18 @@
"""The AEMET OpenData component."""
from __future__ import annotations
import logging
from typing import Any
from aemet_opendata.interface import AEMET
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_NAME,
Platform,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant
from .const import (
CONF_STATION_UPDATES,
DOMAIN,
ENTRY_NAME,
ENTRY_WEATHER_COORDINATOR,
FORECAST_MODES,
PLATFORMS,
RENAMED_FORECAST_SENSOR_KEYS,
)
from .weather_update_coordinator import WeatherUpdateCoordinator
@@ -33,8 +21,6 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up AEMET OpenData as config entry."""
await er.async_migrate_entries(hass, entry.entry_id, async_migrate_entity_entry)
name = entry.data[CONF_NAME]
api_key = entry.data[CONF_API_KEY]
latitude = entry.data[CONF_LATITUDE]
@@ -74,24 +60,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
@callback
def async_migrate_entity_entry(entry: er.RegistryEntry) -> dict[str, Any] | None:
"""Migrate AEMET entity entries.
- Migrates unique ID from old forecast sensors to the new unique ID
"""
if entry.domain != Platform.SENSOR:
return None
for old_key, new_key in RENAMED_FORECAST_SENSOR_KEYS.items():
for forecast_mode in FORECAST_MODES:
old_suffix = f"-forecast-{forecast_mode}-{old_key}"
if entry.unique_id.endswith(old_suffix):
new_suffix = f"-forecast-{forecast_mode}-{new_key}"
return {
"new_unique_id": entry.unique_id.replace(old_suffix, new_suffix)
}
# No migration needed
return None

View File

@@ -17,18 +17,6 @@ from homeassistant.components.weather import (
ATTR_CONDITION_RAINY,
ATTR_CONDITION_SNOWY,
ATTR_CONDITION_SUNNY,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
)
from homeassistant.const import (
DEGREE,
@@ -49,8 +37,16 @@ ENTRY_NAME = "name"
ENTRY_WEATHER_COORDINATOR = "weather_coordinator"
ATTR_API_CONDITION = "condition"
ATTR_API_FORECAST_CONDITION = "condition"
ATTR_API_FORECAST_DAILY = "forecast-daily"
ATTR_API_FORECAST_HOURLY = "forecast-hourly"
ATTR_API_FORECAST_PRECIPITATION = "precipitation"
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY = "precipitation_probability"
ATTR_API_FORECAST_TEMP = "temperature"
ATTR_API_FORECAST_TEMP_LOW = "templow"
ATTR_API_FORECAST_TIME = "datetime"
ATTR_API_FORECAST_WIND_BEARING = "wind_bearing"
ATTR_API_FORECAST_WIND_SPEED = "wind_speed"
ATTR_API_HUMIDITY = "humidity"
ATTR_API_PRESSURE = "pressure"
ATTR_API_RAIN = "rain"
@@ -162,14 +158,14 @@ CONDITIONS_MAP = {
}
FORECAST_MONITORED_CONDITIONS = [
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_API_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP,
ATTR_API_FORECAST_TEMP_LOW,
ATTR_API_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED,
]
MONITORED_CONDITIONS = [
ATTR_API_CONDITION,
@@ -206,53 +202,47 @@ FORECAST_MODE_ATTR_API = {
FORECAST_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_FORECAST_CONDITION,
key=ATTR_API_FORECAST_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_FORECAST_NATIVE_PRECIPITATION,
key=ATTR_API_FORECAST_PRECIPITATION,
name="Precipitation",
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION_PROBABILITY,
key=ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
name="Precipitation probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_FORECAST_NATIVE_TEMP,
key=ATTR_API_FORECAST_TEMP,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_NATIVE_TEMP_LOW,
key=ATTR_API_FORECAST_TEMP_LOW,
name="Temperature Low",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TIME,
key=ATTR_API_FORECAST_TIME,
name="Time",
device_class=SensorDeviceClass.TIMESTAMP,
),
SensorEntityDescription(
key=ATTR_FORECAST_WIND_BEARING,
key=ATTR_API_FORECAST_WIND_BEARING,
name="Wind bearing",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=ATTR_FORECAST_NATIVE_WIND_SPEED,
key=ATTR_API_FORECAST_WIND_SPEED,
name="Wind speed",
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
),
)
RENAMED_FORECAST_SENSOR_KEYS = {
ATTR_FORECAST_PRECIPITATION: ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_TEMP_LOW: ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
}
WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_API_CONDITION,

View File

@@ -10,7 +10,7 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import dt as dt_util
from .const import (
ATTR_FORECAST_TIME,
ATTR_API_FORECAST_TIME,
ATTRIBUTION,
DOMAIN,
ENTRY_NAME,
@@ -135,6 +135,6 @@ class AemetForecastSensor(AbstractAemetSensor):
)
if forecasts:
forecast = forecasts[0].get(self.entity_description.key)
if self.entity_description.key == ATTR_FORECAST_TIME:
if self.entity_description.key == ATTR_API_FORECAST_TIME:
forecast = dt_util.parse_datetime(forecast)
return forecast

View File

@@ -1,5 +1,15 @@
"""Support for the AEMET OpenData service."""
from homeassistant.components.weather import WeatherEntity
from homeassistant.components.weather import (
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
WeatherEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
LENGTH_MILLIMETERS,
@@ -13,6 +23,14 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTR_API_CONDITION,
ATTR_API_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP,
ATTR_API_FORECAST_TEMP_LOW,
ATTR_API_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED,
ATTR_API_HUMIDITY,
ATTR_API_PRESSURE,
ATTR_API_TEMPERATURE,
@@ -24,10 +42,32 @@ from .const import (
ENTRY_WEATHER_COORDINATOR,
FORECAST_MODE_ATTR_API,
FORECAST_MODE_DAILY,
FORECAST_MODE_HOURLY,
FORECAST_MODES,
)
from .weather_update_coordinator import WeatherUpdateCoordinator
FORECAST_MAP = {
FORECAST_MODE_DAILY: {
ATTR_API_FORECAST_CONDITION: ATTR_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP_LOW: ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_API_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
ATTR_API_FORECAST_TIME: ATTR_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING: ATTR_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
},
FORECAST_MODE_HOURLY: {
ATTR_API_FORECAST_CONDITION: ATTR_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_PRECIPITATION: ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_API_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
ATTR_API_FORECAST_TIME: ATTR_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING: ATTR_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
},
}
async def async_setup_entry(
hass: HomeAssistant,
@@ -81,7 +121,12 @@ class AemetWeather(CoordinatorEntity[WeatherUpdateCoordinator], WeatherEntity):
@property
def forecast(self):
"""Return the forecast array."""
return self.coordinator.data[FORECAST_MODE_ATTR_API[self._forecast_mode]]
forecasts = self.coordinator.data[FORECAST_MODE_ATTR_API[self._forecast_mode]]
forecast_map = FORECAST_MAP[self._forecast_mode]
return [
{ha_key: forecast[api_key] for api_key, ha_key in forecast_map.items()}
for forecast in forecasts
]
@property
def humidity(self):

View File

@@ -42,23 +42,21 @@ from aemet_opendata.helpers import (
)
import async_timeout
from homeassistant.components.weather import (
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
)
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util
from .const import (
ATTR_API_CONDITION,
ATTR_API_FORECAST_CONDITION,
ATTR_API_FORECAST_DAILY,
ATTR_API_FORECAST_HOURLY,
ATTR_API_FORECAST_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP,
ATTR_API_FORECAST_TEMP_LOW,
ATTR_API_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED,
ATTR_API_HUMIDITY,
ATTR_API_PRESSURE,
ATTR_API_RAIN,
@@ -402,15 +400,15 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
return None
return {
ATTR_FORECAST_CONDITION: condition,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: self._get_precipitation_prob_day(
ATTR_API_FORECAST_CONDITION: condition,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: self._get_precipitation_prob_day(
day
),
ATTR_FORECAST_NATIVE_TEMP: self._get_temperature_day(day),
ATTR_FORECAST_NATIVE_TEMP_LOW: self._get_temperature_low_day(day),
ATTR_FORECAST_TIME: dt_util.as_utc(date).isoformat(),
ATTR_FORECAST_NATIVE_WIND_SPEED: self._get_wind_speed_day(day),
ATTR_FORECAST_WIND_BEARING: self._get_wind_bearing_day(day),
ATTR_API_FORECAST_TEMP: self._get_temperature_day(day),
ATTR_API_FORECAST_TEMP_LOW: self._get_temperature_low_day(day),
ATTR_API_FORECAST_TIME: dt_util.as_utc(date).isoformat(),
ATTR_API_FORECAST_WIND_SPEED: self._get_wind_speed_day(day),
ATTR_API_FORECAST_WIND_BEARING: self._get_wind_bearing_day(day),
}
def _convert_forecast_hour(self, date, day, hour):
@@ -420,15 +418,15 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
forecast_dt = date.replace(hour=hour, minute=0, second=0)
return {
ATTR_FORECAST_CONDITION: condition,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._calc_precipitation(day, hour),
ATTR_FORECAST_PRECIPITATION_PROBABILITY: self._calc_precipitation_prob(
ATTR_API_FORECAST_CONDITION: condition,
ATTR_API_FORECAST_PRECIPITATION: self._calc_precipitation(day, hour),
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: self._calc_precipitation_prob(
day, hour
),
ATTR_FORECAST_NATIVE_TEMP: self._get_temperature(day, hour),
ATTR_FORECAST_TIME: dt_util.as_utc(forecast_dt).isoformat(),
ATTR_FORECAST_NATIVE_WIND_SPEED: self._get_wind_speed(day, hour),
ATTR_FORECAST_WIND_BEARING: self._get_wind_bearing(day, hour),
ATTR_API_FORECAST_TEMP: self._get_temperature(day, hour),
ATTR_API_FORECAST_TIME: dt_util.as_utc(forecast_dt).isoformat(),
ATTR_API_FORECAST_WIND_SPEED: self._get_wind_speed(day, hour),
ATTR_API_FORECAST_WIND_BEARING: self._get_wind_bearing(day, hour),
}
def _calc_precipitation(self, day, hour):

View File

@@ -102,7 +102,6 @@ class KafkaManager:
self._hass = hass
ssl_context = ssl_util.client_context()
self._producer = AIOKafkaProducer(
loop=hass.loop,
bootstrap_servers=f"{ip_address}:{port}",
compression_type="gzip",
security_protocol=security_protocol,

View File

@@ -2,7 +2,7 @@
"domain": "apache_kafka",
"name": "Apache Kafka",
"documentation": "https://www.home-assistant.io/integrations/apache_kafka",
"requirements": ["aiokafka==0.6.0"],
"requirements": ["aiokafka==0.7.2"],
"codeowners": ["@bachya"],
"iot_class": "local_push",
"loggers": ["aiokafka", "kafka_python"]

View File

@@ -123,6 +123,10 @@ class AppleTVEntity(Entity):
self.atv = None
self.async_write_ha_state()
if self.manager.atv:
# ATV is already connected
_async_connected(self.manager.atv)
self.async_on_remove(
async_dispatcher_connect(
self.hass, f"{SIGNAL_CONNECTED}_{self.unique_id}", _async_connected

View File

@@ -3,7 +3,6 @@ from datetime import timedelta
from http import HTTPStatus
import logging
from aiohttp.hdrs import AUTHORIZATION
import requests
import voluptuous as vol
@@ -67,7 +66,7 @@ class BloomSky:
_LOGGER.debug("Fetching BloomSky update")
response = requests.get(
f"{self.API_URL}?{self._endpoint_argument}",
headers={AUTHORIZATION: self._api_key},
headers={"Authorization": self._api_key},
timeout=10,
)
if response.status_code == HTTPStatus.UNAUTHORIZED:

View File

@@ -37,7 +37,7 @@ class ChromecastInfo:
@property
def friendly_name(self) -> str:
"""Return the UUID."""
"""Return the Friendly Name."""
return self.cast_info.friendly_name
@property

View File

@@ -441,6 +441,19 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
connection_status.status,
)
self._attr_available = new_available
if new_available and not self._cast_info.is_audio_group:
# Poll current group status
for group_uuid in self.mz_mgr.get_multizone_memberships(
self._cast_info.uuid
):
group_media_controller = self.mz_mgr.get_multizone_mediacontroller(
group_uuid
)
if not group_media_controller:
continue
self.multizone_new_media_status(
group_uuid, group_media_controller.status
)
self.schedule_update_ha_state()
def multizone_new_media_status(self, group_uuid, media_status):

View File

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

View File

@@ -113,11 +113,7 @@ async def async_setup_entry(
first = True
for light_id in group.lights:
if (
(light := gateway.api.lights.lights.get(light_id))
and light.ZHATYPE == Light.ZHATYPE
and light.reachable
):
if (light := gateway.api.lights.lights.get(light_id)) and light.reachable:
group.update_color_state(light, update_all_attributes=first)
first = False

View File

@@ -3,7 +3,7 @@
"name": "deCONZ",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/deconz",
"requirements": ["pydeconz==95"],
"requirements": ["pydeconz==97"],
"ssdp": [
{
"manufacturer": "Royal Philips Electronics",

View File

@@ -1,4 +1,7 @@
"""Describe logbook events."""
from __future__ import annotations
from typing import Any
from homeassistant.components.logbook.const import (
LOGBOOK_ENTRY_ENTITY_ID,
@@ -28,12 +31,13 @@ def async_describe_events(hass, async_describe_event):
].get(doorbird_event, event.data.get(ATTR_ENTITY_ID)),
}
domain_data = hass.data[DOMAIN]
domain_data: dict[str, Any] = hass.data[DOMAIN]
for config_entry_id in domain_data:
door_station = domain_data[config_entry_id][DOOR_STATION]
for event in door_station.doorstation_events:
for data in domain_data.values():
if DOOR_STATION not in data:
# We need to skip door_station_event_entity_ids
continue
for event in data[DOOR_STATION].doorstation_events:
async_describe_event(
DOMAIN, f"{DOMAIN}_{event}", async_describe_logbook_event
)

View File

@@ -2,7 +2,7 @@
"domain": "elkm1",
"name": "Elk-M1 Control",
"documentation": "https://www.home-assistant.io/integrations/elkm1",
"requirements": ["elkm1-lib==2.0.0"],
"requirements": ["elkm1-lib==2.0.2"],
"dhcp": [{ "registered_devices": true }, { "macaddress": "00409D*" }],
"codeowners": ["@gwww", "@bdraco"],
"dependencies": ["network"],

View File

@@ -2,7 +2,7 @@
"domain": "envisalink",
"name": "Envisalink",
"documentation": "https://www.home-assistant.io/integrations/envisalink",
"requirements": ["pyenvisalink==4.5"],
"requirements": ["pyenvisalink==4.6"],
"codeowners": ["@ufodone"],
"iot_class": "local_push",
"loggers": ["pyenvisalink"]

View File

@@ -12,8 +12,8 @@ from bleak.backends.scanner import AdvertisementData
from fjaraskupan import Device, State, device_filter
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
@@ -131,6 +131,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
scanner.register_detection_callback(detection_callback)
await scanner.start()
async def on_hass_stop(event: Event) -> None:
await scanner.stop()
entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)
)
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
return True

View File

@@ -113,7 +113,7 @@ class FreeboxRouter:
# According to the doc `syst_datas["sensors"]` is temperature sensors in celsius degree.
# Name and id of sensors may vary under Freebox devices.
for sensor in syst_datas["sensors"]:
self.sensors_temperature[sensor["name"]] = sensor["value"]
self.sensors_temperature[sensor["name"]] = sensor.get("value")
# Connection sensors
connection_datas: dict[str, Any] = await self._api.connection.get_status()

View File

@@ -159,7 +159,7 @@ class FreeboxDiskSensor(FreeboxSensor):
self._disk = disk
self._partition = partition
self._attr_name = f"{partition['label']} {description.name}"
self._unique_id = f"{self._router.mac} {description.key} {self._disk['id']} {self._partition['id']}"
self._attr_unique_id = f"{self._router.mac} {description.key} {self._disk['id']} {self._partition['id']}"
@property
def device_info(self) -> DeviceInfo:

View File

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

View File

@@ -8,6 +8,13 @@
"mode": "Travel Mode"
}
},
"origin_menu": {
"title": "Choose Origin",
"menu_options": {
"origin_coordinates": "Using a map location",
"origin_entity": "Using an entity"
}
},
"origin_coordinates": {
"title": "Choose Origin",
"data": {

View File

@@ -39,6 +39,13 @@
},
"title": "Choose Origin"
},
"origin_menu": {
"menu_options": {
"origin_coordinates": "Using a map location",
"origin_entity": "Using an entity"
},
"title": "Choose Origin"
},
"user": {
"data": {
"api_key": "API Key",

View File

@@ -3,7 +3,7 @@
"name": "HomeKit Controller",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
"requirements": ["aiohomekit==0.7.18"],
"requirements": ["aiohomekit==0.7.20"],
"zeroconf": ["_hap._tcp.local."],
"after_dependencies": ["zeroconf"],
"codeowners": ["@Jc2k", "@bdraco"],

View File

@@ -3,7 +3,7 @@
"name": "HomematicIP Cloud",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
"requirements": ["homematicip==1.0.2"],
"requirements": ["homematicip==1.0.3"],
"codeowners": [],
"quality_scale": "platinum",
"iot_class": "cloud_push",

View File

@@ -2,7 +2,7 @@
"domain": "kaiterra",
"name": "Kaiterra",
"documentation": "https://www.home-assistant.io/integrations/kaiterra",
"requirements": ["kaiterra-async-client==0.0.2"],
"requirements": ["kaiterra-async-client==1.0.0"],
"codeowners": ["@Michsior14"],
"iot_class": "cloud_polling",
"loggers": ["kaiterra_async_client"]

View File

@@ -21,9 +21,6 @@ from homeassistant.components.weather import (
ATTR_CONDITION_SUNNY,
ATTR_CONDITION_WINDY,
ATTR_CONDITION_WINDY_VARIANT,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME,
)
from homeassistant.const import (
DEGREE,
@@ -68,10 +65,15 @@ ATTR_API_FORECAST = "forecast"
UPDATE_LISTENER = "update_listener"
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
ATTR_FORECAST_PRECIPITATION = "precipitation"
ATTR_FORECAST_PRESSURE = "pressure"
ATTR_FORECAST_TEMP = "temperature"
ATTR_FORECAST_TEMP_LOW = "templow"
ATTR_API_FORECAST_CONDITION = "condition"
ATTR_API_FORECAST_PRECIPITATION = "precipitation"
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY = "precipitation_probability"
ATTR_API_FORECAST_PRESSURE = "pressure"
ATTR_API_FORECAST_TEMP = "temperature"
ATTR_API_FORECAST_TEMP_LOW = "templow"
ATTR_API_FORECAST_TIME = "datetime"
ATTR_API_FORECAST_WIND_BEARING = "wind_bearing"
ATTR_API_FORECAST_WIND_SPEED = "wind_speed"
FORECAST_MODE_HOURLY = "hourly"
FORECAST_MODE_DAILY = "daily"
@@ -263,39 +265,39 @@ WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
)
FORECAST_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_FORECAST_CONDITION,
key=ATTR_API_FORECAST_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION,
key=ATTR_API_FORECAST_PRECIPITATION,
name="Precipitation",
native_unit_of_measurement=LENGTH_MILLIMETERS,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION_PROBABILITY,
key=ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
name="Precipitation probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRESSURE,
key=ATTR_API_FORECAST_PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_HPA,
device_class=SensorDeviceClass.PRESSURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP,
key=ATTR_API_FORECAST_TEMP,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP_LOW,
key=ATTR_API_FORECAST_TEMP_LOW,
name="Temperature Low",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TIME,
key=ATTR_API_FORECAST_TIME,
name="Time",
device_class=SensorDeviceClass.TIMESTAMP,
),

View File

@@ -1,7 +1,20 @@
"""Support for the OpenWeatherMap (OWM) service."""
from __future__ import annotations
from homeassistant.components.weather import Forecast, WeatherEntity
from typing import cast
from homeassistant.components.weather import (
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
Forecast,
WeatherEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
LENGTH_MILLIMETERS,
@@ -17,6 +30,14 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
ATTR_API_CONDITION,
ATTR_API_FORECAST,
ATTR_API_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP,
ATTR_API_FORECAST_TEMP_LOW,
ATTR_API_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED,
ATTR_API_HUMIDITY,
ATTR_API_PRESSURE,
ATTR_API_TEMPERATURE,
@@ -31,6 +52,17 @@ from .const import (
)
from .weather_update_coordinator import WeatherUpdateCoordinator
FORECAST_MAP = {
ATTR_API_FORECAST_CONDITION: ATTR_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION: ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_TEMP_LOW: ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_API_FORECAST_TEMP: ATTR_FORECAST_NATIVE_TEMP,
ATTR_API_FORECAST_TIME: ATTR_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING: ATTR_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED: ATTR_FORECAST_NATIVE_WIND_SPEED,
}
async def async_setup_entry(
hass: HomeAssistant,
@@ -109,7 +141,16 @@ class OpenWeatherMapWeather(WeatherEntity):
@property
def forecast(self) -> list[Forecast] | None:
"""Return the forecast array."""
return self._weather_coordinator.data[ATTR_API_FORECAST]
api_forecasts = self._weather_coordinator.data[ATTR_API_FORECAST]
forecasts = [
{
ha_key: forecast[api_key]
for api_key, ha_key in FORECAST_MAP.items()
if api_key in forecast
}
for forecast in api_forecasts
]
return cast(list[Forecast], forecasts)
@property
def available(self) -> bool:

View File

@@ -8,15 +8,6 @@ from pyowm.commons.exceptions import APIRequestError, UnauthorizedError
from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_SUNNY,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
)
from homeassistant.helpers import sun
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@@ -29,6 +20,15 @@ from .const import (
ATTR_API_DEW_POINT,
ATTR_API_FEELS_LIKE_TEMPERATURE,
ATTR_API_FORECAST,
ATTR_API_FORECAST_CONDITION,
ATTR_API_FORECAST_PRECIPITATION,
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_API_FORECAST_PRESSURE,
ATTR_API_FORECAST_TEMP,
ATTR_API_FORECAST_TEMP_LOW,
ATTR_API_FORECAST_TIME,
ATTR_API_FORECAST_WIND_BEARING,
ATTR_API_FORECAST_WIND_SPEED,
ATTR_API_HUMIDITY,
ATTR_API_PRECIPITATION_KIND,
ATTR_API_PRESSURE,
@@ -158,19 +158,19 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
def _convert_forecast(self, entry):
"""Convert the forecast data."""
forecast = {
ATTR_FORECAST_TIME: dt.utc_from_timestamp(
ATTR_API_FORECAST_TIME: dt.utc_from_timestamp(
entry.reference_time("unix")
).isoformat(),
ATTR_FORECAST_NATIVE_PRECIPITATION: self._calc_precipitation(
ATTR_API_FORECAST_PRECIPITATION: self._calc_precipitation(
entry.rain, entry.snow
),
ATTR_FORECAST_PRECIPITATION_PROBABILITY: (
ATTR_API_FORECAST_PRECIPITATION_PROBABILITY: (
round(entry.precipitation_probability * 100)
),
ATTR_FORECAST_NATIVE_PRESSURE: entry.pressure.get("press"),
ATTR_FORECAST_NATIVE_WIND_SPEED: entry.wind().get("speed"),
ATTR_FORECAST_WIND_BEARING: entry.wind().get("deg"),
ATTR_FORECAST_CONDITION: self._get_condition(
ATTR_API_FORECAST_PRESSURE: entry.pressure.get("press"),
ATTR_API_FORECAST_WIND_SPEED: entry.wind().get("speed"),
ATTR_API_FORECAST_WIND_BEARING: entry.wind().get("deg"),
ATTR_API_FORECAST_CONDITION: self._get_condition(
entry.weather_code, entry.reference_time("unix")
),
ATTR_API_CLOUDS: entry.clouds,
@@ -178,16 +178,12 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
temperature_dict = entry.temperature("celsius")
if "max" in temperature_dict and "min" in temperature_dict:
forecast[ATTR_FORECAST_NATIVE_TEMP] = entry.temperature("celsius").get(
"max"
)
forecast[ATTR_FORECAST_NATIVE_TEMP_LOW] = entry.temperature("celsius").get(
forecast[ATTR_API_FORECAST_TEMP] = entry.temperature("celsius").get("max")
forecast[ATTR_API_FORECAST_TEMP_LOW] = entry.temperature("celsius").get(
"min"
)
else:
forecast[ATTR_FORECAST_NATIVE_TEMP] = entry.temperature("celsius").get(
"temp"
)
forecast[ATTR_API_FORECAST_TEMP] = entry.temperature("celsius").get("temp")
return forecast

View File

@@ -183,7 +183,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.data[CONF_IP_ADDRESS],
entry.data[CONF_PASSWORD],
port=entry.data[CONF_PORT],
ssl=entry.data.get(CONF_SSL, DEFAULT_SSL),
use_ssl=entry.data.get(CONF_SSL, DEFAULT_SSL),
)
except RainMachineError as err:
raise ConfigEntryNotReady from err

View File

@@ -32,7 +32,7 @@ async def async_get_controller(
websession = aiohttp_client.async_get_clientsession(hass)
client = Client(session=websession)
try:
await client.load_local(ip_address, password, port=port, ssl=ssl)
await client.load_local(ip_address, password, port=port, use_ssl=ssl)
except RainMachineError:
return None
else:

View File

@@ -3,7 +3,7 @@
"name": "RainMachine",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/rainmachine",
"requirements": ["regenmaschine==2022.06.1"],
"requirements": ["regenmaschine==2022.07.0"],
"codeowners": ["@bachya"],
"iot_class": "local_polling",
"homekit": {

View File

@@ -2,7 +2,7 @@
"domain": "satel_integra",
"name": "Satel Integra",
"documentation": "https://www.home-assistant.io/integrations/satel_integra",
"requirements": ["satel_integra==0.3.4"],
"requirements": ["satel_integra==0.3.7"],
"codeowners": [],
"iot_class": "local_push",
"loggers": ["satel_integra"]

View File

@@ -3,7 +3,7 @@
"name": "SkyBell",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/skybell",
"requirements": ["aioskybell==22.6.1"],
"requirements": ["aioskybell==22.7.0"],
"dependencies": ["ffmpeg"],
"codeowners": ["@tkdrob"],
"iot_class": "cloud_polling",

View File

@@ -4,7 +4,7 @@
"config_flow": true,
"iot_class": "local_push",
"documentation": "https://www.home-assistant.io/integrations/slimproto",
"requirements": ["aioslimproto==2.0.1"],
"requirements": ["aioslimproto==2.1.1"],
"codeowners": ["@marcelveldt"],
"after_dependencies": ["media_source"]
}

View File

@@ -69,6 +69,7 @@ from .speaker import SonosMedia, SonosSpeaker
_LOGGER = logging.getLogger(__name__)
LONG_SERVICE_TIMEOUT = 30.0
UNJOIN_SERVICE_TIMEOUT = 0.1
VOLUME_INCREMENT = 2
REPEAT_TO_SONOS = {
@@ -775,7 +776,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
async def async_unjoin_player(self):
"""Remove this player from any group.
Coalesces all calls within 0.5s to allow use of SonosSpeaker.unjoin_multi()
Coalesces all calls within UNJOIN_SERVICE_TIMEOUT to allow use of SonosSpeaker.unjoin_multi()
which optimizes the order in which speakers are removed from their groups.
Removing coordinators last better preserves playqueues on the speakers.
"""
@@ -785,6 +786,9 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
async def async_process_unjoin(now: datetime.datetime) -> None:
"""Process the unjoin with all remove requests within the coalescing period."""
unjoin_data = sonos_data.unjoin_data.pop(household_id)
_LOGGER.debug(
"Processing unjoins for %s", [x.zone_name for x in unjoin_data.speakers]
)
await SonosSpeaker.unjoin_multi(self.hass, unjoin_data.speakers)
unjoin_data.event.set()
@@ -794,6 +798,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
unjoin_data = sonos_data.unjoin_data[household_id] = UnjoinData(
speakers=[self.speaker]
)
async_call_later(self.hass, 0.5, async_process_unjoin)
async_call_later(self.hass, UNJOIN_SERVICE_TIMEOUT, async_process_unjoin)
_LOGGER.debug("Requesting unjoin for %s", self.speaker.zone_name)
await unjoin_data.event.wait()

View File

@@ -579,7 +579,7 @@ UNITS = (
),
UnitOfMeasurement(
unit=TEMP_CELSIUS,
aliases={"°c", "c", "celsius"},
aliases={"°c", "c", "celsius", ""},
device_classes={SensorDeviceClass.TEMPERATURE},
),
UnitOfMeasurement(

View File

@@ -80,7 +80,7 @@ class UnifiDeviceScanner(DeviceScanner):
def _connect(self):
"""Connect to the Unifi AP SSH server."""
self.ssh = pxssh.pxssh()
self.ssh = pxssh.pxssh(options={"HostKeyAlgorithms": "ssh-rsa"})
try:
self.ssh.login(
self.host, self.username, password=self.password, port=self.port

View File

@@ -10,7 +10,6 @@ import logging
import os
from typing import Union
from aiohttp.hdrs import USER_AGENT
import requests
import voluptuous as vol
@@ -275,7 +274,7 @@ class ZamgData:
"""The class for handling the data retrieval."""
API_URL = "http://www.zamg.ac.at/ogd/"
API_HEADERS = {USER_AGENT: f"home-assistant.zamg/ {__version__}"}
API_HEADERS = {"User-Agent": f"home-assistant.zamg/ {__version__}"}
def __init__(self, station_id):
"""Initialize the probe."""

View File

@@ -188,7 +188,7 @@ class FrostLock(BinarySensor, id_suffix="frost_lock"):
_attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.LOCK
@MULTI_MATCH(channel_names="ikea_airpurifier", models={"STARKVIND Air purifier"})
@MULTI_MATCH(channel_names="ikea_airpurifier")
class ReplaceFilter(BinarySensor, id_suffix="replace_filter"):
"""ZHA BinarySensor."""

View File

@@ -141,7 +141,7 @@ class BaseLight(LogMixin, light.LightEntity):
self._color_channel = None
self._identify_channel = None
self._default_transition = None
self._color_mode = ColorMode.UNKNOWN # Set by sub classes
self._attr_color_mode = ColorMode.UNKNOWN # Set by sub classes
@property
def extra_state_attributes(self) -> dict[str, Any]:
@@ -159,11 +159,6 @@ class BaseLight(LogMixin, light.LightEntity):
return False
return self._state
@property
def color_mode(self):
"""Return the color mode of this light."""
return self._color_mode
@property
def brightness(self):
"""Return the brightness of this light."""
@@ -309,7 +304,7 @@ class BaseLight(LogMixin, light.LightEntity):
if isinstance(result, Exception) or result[1] is not Status.SUCCESS:
self.debug("turned on: %s", t_log)
return
self._color_mode = ColorMode.COLOR_TEMP
self._attr_color_mode = ColorMode.COLOR_TEMP
self._color_temp = temperature
self._hs_color = None
@@ -323,7 +318,7 @@ class BaseLight(LogMixin, light.LightEntity):
if isinstance(result, Exception) or result[1] is not Status.SUCCESS:
self.debug("turned on: %s", t_log)
return
self._color_mode = ColorMode.HS
self._attr_color_mode = ColorMode.HS
self._hs_color = hs_color
self._color_temp = None
@@ -451,13 +446,13 @@ class Light(BaseLight, ZhaEntity):
self._attr_supported_color_modes
)
if len(self._attr_supported_color_modes) == 1:
self._color_mode = next(iter(self._attr_supported_color_modes))
self._attr_color_mode = next(iter(self._attr_supported_color_modes))
else: # Light supports color_temp + hs, determine which mode the light is in
assert self._color_channel
if self._color_channel.color_mode == Color.ColorMode.Color_temperature:
self._color_mode = ColorMode.COLOR_TEMP
self._attr_color_mode = ColorMode.COLOR_TEMP
else:
self._color_mode = ColorMode.HS
self._attr_color_mode = ColorMode.HS
if self._identify_channel:
self._supported_features |= light.LightEntityFeature.FLASH
@@ -518,7 +513,7 @@ class Light(BaseLight, ZhaEntity):
if "off_brightness" in last_state.attributes:
self._off_brightness = last_state.attributes["off_brightness"]
if "color_mode" in last_state.attributes:
self._color_mode = ColorMode(last_state.attributes["color_mode"])
self._attr_color_mode = ColorMode(last_state.attributes["color_mode"])
if "color_temp" in last_state.attributes:
self._color_temp = last_state.attributes["color_temp"]
if "hs_color" in last_state.attributes:
@@ -558,13 +553,13 @@ class Light(BaseLight, ZhaEntity):
if (color_mode := results.get("color_mode")) is not None:
if color_mode == Color.ColorMode.Color_temperature:
self._color_mode = ColorMode.COLOR_TEMP
self._attr_color_mode = ColorMode.COLOR_TEMP
color_temp = results.get("color_temperature")
if color_temp is not None and color_mode:
self._color_temp = color_temp
self._hs_color = None
else:
self._color_mode = ColorMode.HS
self._attr_color_mode = ColorMode.HS
color_x = results.get("current_x")
color_y = results.get("current_y")
if color_x is not None and color_y is not None:
@@ -650,7 +645,7 @@ class LightGroup(BaseLight, ZhaGroupEntity):
CONF_DEFAULT_LIGHT_TRANSITION,
0,
)
self._color_mode = None
self._attr_color_mode = None
async def async_added_to_hass(self):
"""Run when about to be added to hass."""

View File

@@ -525,9 +525,7 @@ class TimerDurationMinutes(ZHANumberConfigurationEntity, id_suffix="timer_durati
_zcl_attribute: str = "timer_duration"
@CONFIG_DIAGNOSTIC_MATCH(
channel_names="ikea_airpurifier", models={"STARKVIND Air purifier"}
)
@CONFIG_DIAGNOSTIC_MATCH(channel_names="ikea_airpurifier")
class FilterLifeTime(ZHANumberConfigurationEntity, id_suffix="filter_life_time"):
"""Representation of a ZHA timer duration configuration entity."""

View File

@@ -472,25 +472,8 @@ class SmartEnergyMetering(Sensor):
@MULTI_MATCH(
channel_names=CHANNEL_SMARTENERGY_METERING,
models={"TS011F"},
stop_on_match_group=CHANNEL_SMARTENERGY_METERING,
)
class PolledSmartEnergyMetering(SmartEnergyMetering):
"""Polled metering sensor."""
@property
def should_poll(self) -> bool:
"""Poll the entity for current state."""
return True
async def async_update(self) -> None:
"""Retrieve latest state."""
if not self.available:
return
await self._channel.async_force_update()
@MULTI_MATCH(channel_names=CHANNEL_SMARTENERGY_METERING)
class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered"):
"""Smart Energy Metering summation sensor."""
@@ -523,6 +506,26 @@ class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered")
return round(cooked, 3)
@MULTI_MATCH(
channel_names=CHANNEL_SMARTENERGY_METERING,
models={"TS011F"},
stop_on_match_group=CHANNEL_SMARTENERGY_METERING,
)
class PolledSmartEnergySummation(SmartEnergySummation):
"""Polled Smart Energy Metering summation sensor."""
@property
def should_poll(self) -> bool:
"""Poll the entity for current state."""
return True
async def async_update(self) -> None:
"""Retrieve latest state."""
if not self.available:
return
await self._channel.async_force_update()
@MULTI_MATCH(channel_names=CHANNEL_PRESSURE)
class Pressure(Sensor):
"""Pressure sensor."""
@@ -810,7 +813,7 @@ class TimeLeft(Sensor, id_suffix="time_left"):
_unit = TIME_MINUTES
@MULTI_MATCH(channel_names="ikea_airpurifier", models={"STARKVIND Air purifier"})
@MULTI_MATCH(channel_names="ikea_airpurifier")
class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"):
"""Sensor that displays device run time (in minutes)."""
@@ -820,7 +823,7 @@ class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"):
_unit = TIME_MINUTES
@MULTI_MATCH(channel_names="ikea_airpurifier", models={"STARKVIND Air purifier"})
@MULTI_MATCH(channel_names="ikea_airpurifier")
class IkeaFilterRunTime(Sensor, id_suffix="filter_run_time"):
"""Sensor that displays run time of the current filter (in minutes)."""

View File

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

View File

@@ -6,7 +6,7 @@ import logging
from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union, cast
from homeassistant import config_entries
from homeassistant.components import dhcp, mqtt, onboarding, ssdp, zeroconf
from homeassistant.components import dhcp, onboarding, ssdp, zeroconf
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
@@ -15,6 +15,9 @@ from .typing import UNDEFINED, DiscoveryInfoType, UndefinedType
if TYPE_CHECKING:
import asyncio
from homeassistant.components import mqtt
_R = TypeVar("_R", bound="Awaitable[bool] | bool")
DiscoveryFunctionType = Callable[[HomeAssistant], _R]

View File

@@ -6,7 +6,7 @@ aiohttp_cors==0.7.0
astral==2.2
async-upnp-client==0.31.2
async_timeout==4.0.2
atomicwrites==1.4.0
atomicwrites-homeassistant==1.4.1
attrs==21.2.0
awesomeversion==22.6.0
bcrypt==3.1.7
@@ -14,8 +14,8 @@ certifi>=2021.5.30
ciso8601==2.2.0
cryptography==36.0.2
fnvhash==0.1.0
hass-nabucasa==0.54.0
home-assistant-frontend==20220630.0
hass-nabucasa==0.54.1
home-assistant-frontend==20220707.0
httpx==0.23.0
ifaddr==0.1.7
jinja2==3.1.2

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2022.7.0b4"
version = "2022.7.2"
license = {text = "Apache-2.0"}
description = "Open-source home automation platform running on Python 3."
readme = "README.rst"
@@ -28,7 +28,7 @@ dependencies = [
"astral==2.2",
"async_timeout==4.0.2",
"attrs==21.2.0",
"atomicwrites==1.4.0",
"atomicwrites-homeassistant==1.4.1",
"awesomeversion==22.6.0",
"bcrypt==3.1.7",
"certifi>=2021.5.30",

View File

@@ -5,7 +5,7 @@ aiohttp==3.8.1
astral==2.2
async_timeout==4.0.2
attrs==21.2.0
atomicwrites==1.4.0
atomicwrites-homeassistant==1.4.1
awesomeversion==22.6.0
bcrypt==3.1.7
certifi>=2021.5.30

View File

@@ -168,7 +168,7 @@ aioguardian==2022.03.2
aioharmony==0.2.9
# homeassistant.components.homekit_controller
aiohomekit==0.7.18
aiohomekit==0.7.20
# homeassistant.components.emulated_hue
# homeassistant.components.http
@@ -181,7 +181,7 @@ aiohue==4.4.2
aioimaplib==1.0.0
# homeassistant.components.apache_kafka
aiokafka==0.6.0
aiokafka==0.7.2
# homeassistant.components.kef
aiokef==0.2.16
@@ -247,10 +247,10 @@ aiosenz==1.0.0
aioshelly==2.0.0
# homeassistant.components.skybell
aioskybell==22.6.1
aioskybell==22.7.0
# homeassistant.components.slimproto
aioslimproto==2.0.1
aioslimproto==2.1.1
# homeassistant.components.steamist
aiosteamist==0.3.2
@@ -586,7 +586,7 @@ elgato==3.0.0
eliqonline==1.2.2
# homeassistant.components.elkm1
elkm1-lib==2.0.0
elkm1-lib==2.0.2
# homeassistant.components.elmax
elmax_api==0.0.2
@@ -795,7 +795,7 @@ habitipy==0.2.0
hangups==0.4.18
# homeassistant.components.cloud
hass-nabucasa==0.54.0
hass-nabucasa==0.54.1
# homeassistant.components.splunk
hass_splunk==0.1.1
@@ -828,13 +828,13 @@ hole==0.7.0
holidays==0.14.2
# homeassistant.components.frontend
home-assistant-frontend==20220630.0
home-assistant-frontend==20220707.0
# homeassistant.components.home_connect
homeconnect==0.7.1
# homeassistant.components.homematicip_cloud
homematicip==1.0.2
homematicip==1.0.3
# homeassistant.components.home_plus_control
homepluscontrol==0.0.5
@@ -912,7 +912,7 @@ jellyfin-apiclient-python==1.8.1
jsonpath==0.82
# homeassistant.components.kaiterra
kaiterra-async-client==0.0.2
kaiterra-async-client==1.0.0
# homeassistant.components.keba
keba-kecontact==1.1.0
@@ -1444,7 +1444,7 @@ pydaikin==2.7.0
pydanfossair==0.1.0
# homeassistant.components.deconz
pydeconz==95
pydeconz==97
# homeassistant.components.delijn
pydelijn==1.0.0
@@ -1477,7 +1477,7 @@ pyeight==0.3.0
pyemby==1.8
# homeassistant.components.envisalink
pyenvisalink==4.5
pyenvisalink==4.6
# homeassistant.components.ephember
pyephember==0.3.1
@@ -2065,7 +2065,7 @@ raincloudy==0.0.7
raspyrfm-client==1.2.8
# homeassistant.components.rainmachine
regenmaschine==2022.06.1
regenmaschine==2022.07.0
# homeassistant.components.renault
renault-api==0.1.11
@@ -2125,7 +2125,7 @@ samsungctl[websocket]==0.7.1
samsungtvws[async,encrypted]==2.5.0
# homeassistant.components.satel_integra
satel_integra==0.3.4
satel_integra==0.3.7
# homeassistant.components.dhcp
scapy==2.4.5

View File

@@ -152,7 +152,7 @@ aioguardian==2022.03.2
aioharmony==0.2.9
# homeassistant.components.homekit_controller
aiohomekit==0.7.18
aiohomekit==0.7.20
# homeassistant.components.emulated_hue
# homeassistant.components.http
@@ -162,7 +162,7 @@ aiohttp_cors==0.7.0
aiohue==4.4.2
# homeassistant.components.apache_kafka
aiokafka==0.6.0
aiokafka==0.7.2
# homeassistant.components.lookin
aiolookin==0.1.1
@@ -216,10 +216,10 @@ aiosenz==1.0.0
aioshelly==2.0.0
# homeassistant.components.skybell
aioskybell==22.6.1
aioskybell==22.7.0
# homeassistant.components.slimproto
aioslimproto==2.0.1
aioslimproto==2.1.1
# homeassistant.components.steamist
aiosteamist==0.3.2
@@ -426,7 +426,7 @@ eagle100==0.1.1
elgato==3.0.0
# homeassistant.components.elkm1
elkm1-lib==2.0.0
elkm1-lib==2.0.2
# homeassistant.components.elmax
elmax_api==0.0.2
@@ -574,7 +574,7 @@ habitipy==0.2.0
hangups==0.4.18
# homeassistant.components.cloud
hass-nabucasa==0.54.0
hass-nabucasa==0.54.1
# homeassistant.components.tasmota
hatasmota==0.5.1
@@ -595,13 +595,13 @@ hole==0.7.0
holidays==0.14.2
# homeassistant.components.frontend
home-assistant-frontend==20220630.0
home-assistant-frontend==20220707.0
# homeassistant.components.home_connect
homeconnect==0.7.1
# homeassistant.components.homematicip_cloud
homematicip==1.0.2
homematicip==1.0.3
# homeassistant.components.home_plus_control
homepluscontrol==0.0.5
@@ -974,7 +974,7 @@ pycoolmasternet-async==0.1.2
pydaikin==2.7.0
# homeassistant.components.deconz
pydeconz==95
pydeconz==97
# homeassistant.components.dexcom
pydexcom==0.2.3
@@ -1376,7 +1376,7 @@ radios==0.1.1
radiotherm==2.1.0
# homeassistant.components.rainmachine
regenmaschine==2022.06.1
regenmaschine==2022.07.0
# homeassistant.components.renault
renault-api==0.1.11

View File

@@ -2,15 +2,11 @@
from unittest.mock import patch
import pytest
import requests_mock
from homeassistant.components.aemet.const import DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
import homeassistant.util.dt as dt_util
from .util import aemet_requests_mock
@@ -46,83 +42,3 @@ async def test_unload_entry(hass):
await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.NOT_LOADED
@pytest.mark.parametrize(
"old_unique_id,new_unique_id",
[
# Sensors which should be migrated
(
"aemet_unique_id-forecast-daily-precipitation",
"aemet_unique_id-forecast-daily-native_precipitation",
),
(
"aemet_unique_id-forecast-daily-temperature",
"aemet_unique_id-forecast-daily-native_temperature",
),
(
"aemet_unique_id-forecast-daily-templow",
"aemet_unique_id-forecast-daily-native_templow",
),
(
"aemet_unique_id-forecast-daily-wind_speed",
"aemet_unique_id-forecast-daily-native_wind_speed",
),
(
"aemet_unique_id-forecast-hourly-precipitation",
"aemet_unique_id-forecast-hourly-native_precipitation",
),
(
"aemet_unique_id-forecast-hourly-temperature",
"aemet_unique_id-forecast-hourly-native_temperature",
),
(
"aemet_unique_id-forecast-hourly-templow",
"aemet_unique_id-forecast-hourly-native_templow",
),
(
"aemet_unique_id-forecast-hourly-wind_speed",
"aemet_unique_id-forecast-hourly-native_wind_speed",
),
# Already migrated
(
"aemet_unique_id-forecast-daily-native_templow",
"aemet_unique_id-forecast-daily-native_templow",
),
# No migration needed
(
"aemet_unique_id-forecast-daily-condition",
"aemet_unique_id-forecast-daily-condition",
),
],
)
async def test_migrate_unique_id_sensor(
hass: HomeAssistant,
old_unique_id: str,
new_unique_id: str,
) -> None:
"""Test migration of unique_id."""
now = dt_util.parse_datetime("2021-01-09 12:00:00+00:00")
with patch("homeassistant.util.dt.now", return_value=now), patch(
"homeassistant.util.dt.utcnow", return_value=now
), requests_mock.mock() as _m:
aemet_requests_mock(_m)
config_entry = MockConfigEntry(
domain=DOMAIN, unique_id="aemet_unique_id", data=CONFIG
)
config_entry.add_to_hass(hass)
entity_registry = er.async_get(hass)
entity: er.RegistryEntry = entity_registry.async_get_or_create(
domain=SENSOR_DOMAIN,
platform=DOMAIN,
unique_id=old_unique_id,
config_entry=config_entry,
)
assert entity.unique_id == old_unique_id
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_migrated = entity_registry.async_get(entity.entity_id)
assert entity_migrated
assert entity_migrated.unique_id == new_unique_id

View File

@@ -731,6 +731,20 @@ async def test_entity_availability(hass: HomeAssistant):
state = hass.states.get(entity_id)
assert state.state == "off"
connection_status = MagicMock()
connection_status.status = "LOST"
conn_status_cb(connection_status)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "unavailable"
connection_status = MagicMock()
connection_status.status = "CONNECTED"
conn_status_cb(connection_status)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "off"
connection_status = MagicMock()
connection_status.status = "DISCONNECTED"
conn_status_cb(connection_status)
@@ -738,6 +752,14 @@ async def test_entity_availability(hass: HomeAssistant):
state = hass.states.get(entity_id)
assert state.state == "unavailable"
# Can't reconnect after receiving DISCONNECTED
connection_status = MagicMock()
connection_status.status = "CONNECTED"
conn_status_cb(connection_status)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "unavailable"
@pytest.mark.parametrize("port,entry_type", ((8009, None), (12345, None)))
async def test_device_registry(hass: HomeAssistant, hass_ws_client, port, entry_type):
@@ -1675,6 +1697,59 @@ async def test_group_media_states(hass, mz_mock):
assert state.state == "playing"
async def test_group_media_states_early(hass, mz_mock):
"""Test media states are read from group if entity has no state.
This tests case asserts group state is polled when the player is created.
"""
entity_id = "media_player.speaker"
reg = er.async_get(hass)
info = get_fake_chromecast_info()
mz_mock.get_multizone_memberships = MagicMock(return_value=[str(FakeGroupUUID)])
mz_mock.get_multizone_mediacontroller = MagicMock(
return_value=MagicMock(status=MagicMock(images=None, player_state="BUFFERING"))
)
chromecast, _ = await async_setup_media_player_cast(hass, info)
_, conn_status_cb, _, _ = get_status_callbacks(chromecast, mz_mock)
state = hass.states.get(entity_id)
assert state is not None
assert state.name == "Speaker"
assert state.state == "unavailable"
assert entity_id == reg.async_get_entity_id("media_player", "cast", str(info.uuid))
# Check group state is polled when player is first created
connection_status = MagicMock()
connection_status.status = "CONNECTED"
conn_status_cb(connection_status)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == "buffering"
connection_status = MagicMock()
connection_status.status = "LOST"
conn_status_cb(connection_status)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == "unavailable"
# Check group state is polled when player reconnects
mz_mock.get_multizone_mediacontroller = MagicMock(
return_value=MagicMock(status=MagicMock(images=None, player_state="PLAYING"))
)
connection_status = MagicMock()
connection_status.status = "CONNECTED"
conn_status_cb(connection_status)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == "playing"
async def test_group_media_control(hass, mz_mock, quick_play_mock):
"""Test media controls are handled by group if entity has no state."""
entity_id = "media_player.speaker"

View File

@@ -816,6 +816,37 @@ async def test_dont_add_sensor_if_state_is_none(
assert len(hass.states.async_all()) == 0
async def test_air_quality_sensor_without_ppb(hass, aioclient_mock):
"""Test sensor with scaled data is not created if state is None."""
data = {
"sensors": {
"1": {
"config": {
"on": True,
"reachable": True,
},
"ep": 2,
"etag": "c2d2e42396f7c78e11e46c66e2ec0200",
"lastseen": "2020-11-20T22:48Z",
"manufacturername": "BOSCH",
"modelid": "AIR",
"name": "BOSCH Air quality sensor",
"state": {
"airquality": "poor",
"lastupdated": "2020-11-20T22:48:00.209",
},
"swversion": "20200402",
"type": "ZHAAirQuality",
"uniqueid": "00:00:00:00:00:00:00:00-02-fdef",
}
}
}
with patch.dict(DECONZ_WEB_REQUEST, data):
await setup_deconz_integration(hass, aioclient_mock)
assert len(hass.states.async_all()) == 1
async def test_add_battery_later(hass, aioclient_mock, mock_deconz_websocket):
"""Test that a sensor without an initial battery state creates a battery sensor once state exist."""
data = {

View File

@@ -1,12 +1,10 @@
"""The tests for the Demo component."""
from contextlib import suppress
import json
import os
from unittest.mock import patch
import pytest
from homeassistant.components.demo import DOMAIN
from homeassistant.components.device_tracker.legacy import YAML_DEVICES
from homeassistant.components.recorder import get_instance
from homeassistant.components.recorder.statistics import list_statistic_ids
from homeassistant.helpers.json import JSONEncoder
@@ -22,11 +20,10 @@ def mock_history(hass):
@pytest.fixture(autouse=True)
def demo_cleanup(hass):
"""Clean up device tracker demo file."""
yield
with suppress(FileNotFoundError):
os.remove(hass.config.path(YAML_DEVICES))
def mock_device_tracker_update_config(hass):
"""Prevent device tracker from creating known devices file."""
with patch("homeassistant.components.device_tracker.legacy.update_config"):
yield
async def test_setting_up_demo(hass):

View File

@@ -28,6 +28,8 @@ from homeassistant.helpers.json import JSONEncoder
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from . import common
from tests.common import (
assert_setup_component,
async_fire_time_changed,
@@ -35,7 +37,6 @@ from tests.common import (
mock_restore_cache,
patch_yaml_files,
)
from tests.components.device_tracker import common
TEST_PLATFORM = {device_tracker.DOMAIN: {CONF_PLATFORM: "test"}}
@@ -165,6 +166,7 @@ async def test_setup_without_yaml_file(hass, enable_custom_integrations):
"""Test with no YAML file."""
with assert_setup_component(1, device_tracker.DOMAIN):
assert await async_setup_component(hass, device_tracker.DOMAIN, TEST_PLATFORM)
await hass.async_block_till_done()
async def test_gravatar(hass):
@@ -210,10 +212,11 @@ async def test_gravatar_and_picture(hass):
@patch("homeassistant.components.demo.device_tracker.setup_scanner", autospec=True)
async def test_discover_platform(mock_demo_setup_scanner, mock_see, hass):
"""Test discovery of device_tracker demo platform."""
await discovery.async_load_platform(
hass, device_tracker.DOMAIN, "demo", {"test_key": "test_val"}, {"bla": {}}
)
await hass.async_block_till_done()
with patch("homeassistant.components.device_tracker.legacy.update_config"):
await discovery.async_load_platform(
hass, device_tracker.DOMAIN, "demo", {"test_key": "test_val"}, {"bla": {}}
)
await hass.async_block_till_done()
assert device_tracker.DOMAIN in hass.config.components
assert mock_demo_setup_scanner.called
assert mock_demo_setup_scanner.call_args[0] == (

View File

@@ -22,6 +22,7 @@ DATA_SYSTEM_GET_CONFIG = {
"fans": [{"id": "fan0_speed", "name": "Ventilateur 1", "value": 2130}],
"sensors": [
{"id": "temp_hdd", "name": "Disque dur", "value": 40},
{"id": "temp_hdd2", "name": "Disque dur 2"},
{"id": "temp_sw", "name": "Température Switch", "value": 50},
{"id": "temp_cpum", "name": "Température CPU M", "value": 60},
{"id": "temp_cpub", "name": "Température CPU B", "value": 56},
@@ -123,7 +124,42 @@ DATA_STORAGE_GET_DISKS = [
"path": "L0Rpc3F1ZSBkdXI=",
}
],
}
},
{
"idle_duration": 8290,
"read_error_requests": 0,
"read_requests": 2326826,
"spinning": False,
"table_type": "gpt",
"firmware": "0001",
"type": "sata",
"idle": True,
"connector": 0,
"id": 2000,
"write_error_requests": 0,
"state": "enabled",
"write_requests": 122733632,
"total_bytes": 2000000000000,
"model": "ST2000LM015-2E8174",
"active_duration": 0,
"temp": 0,
"serial": "WDZYJ27Q",
"partitions": [
{
"fstype": "ext4",
"total_bytes": 1960000000000,
"label": "Disque 2",
"id": 2001,
"internal": False,
"fsck_result": "no_run_yet",
"state": "mounted",
"disk_id": 2000,
"free_bytes": 1880000000000,
"used_bytes": 85410000000,
"path": "L0Rpc3F1ZSAy",
}
],
},
]
# switch