Skip to content
Merged

0.107.5 #33118

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/huawei_lte/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"documentation": "https://www.home-assistant.io/integrations/huawei_lte",
"requirements": [
"getmac==0.8.1",
"huawei-lte-api==1.4.10",
"huawei-lte-api==1.4.11",
"stringcase==1.2.0",
"url-normalize==1.4.1"
],
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/onvif/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,4 +505,6 @@ def name(self):
@property
def unique_id(self) -> Optional[str]:
"""Return a unique ID."""
if self._profile_index:
return f"{self._mac}_{self._profile_index}"
return self._mac
7 changes: 6 additions & 1 deletion homeassistant/components/samsungtv/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def try_connect(self):
CONF_TIMEOUT: 31,
}

result = None
try:
LOGGER.debug("Try config: %s", config)
with SamsungTVWS(
Expand All @@ -223,9 +224,13 @@ def try_connect(self):
return RESULT_SUCCESS
except WebSocketException:
LOGGER.debug("Working but unsupported config: %s", config)
return RESULT_NOT_SUPPORTED
result = RESULT_NOT_SUPPORTED
except (OSError, ConnectionFailure) as err:
LOGGER.debug("Failing config: %s, error: %s", config, err)
# pylint: disable=useless-else-on-loop
else:
if result:
return result

return RESULT_NOT_SUCCESSFUL

Expand Down
35 changes: 25 additions & 10 deletions homeassistant/components/tankerkoenig/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Ask tankerkoenig.de for petrol price information."""
from datetime import timedelta
import logging
from math import ceil

import pytankerkoenig
import voluptuous as vol
Expand Down Expand Up @@ -164,27 +165,41 @@ def setup(self, latitude, longitude, radius, additional_stations):
)
return False
self.add_station(additional_station_data["station"])
if len(self.stations) > 10:
_LOGGER.warning(
"Found more than 10 stations to check. "
"This might invalidate your api-key on the long run. "
"Try using a smaller radius"
)
return True

async def fetch_data(self):
"""Get the latest data from tankerkoenig.de."""
_LOGGER.debug("Fetching new data from tankerkoenig.de")
station_ids = list(self.stations)
data = await self._hass.async_add_executor_job(
pytankerkoenig.getPriceList, self._api_key, station_ids
)

if data["ok"]:
prices = {}

# The API seems to only return at most 10 results, so split the list in chunks of 10
# and merge it together.
for index in range(ceil(len(station_ids) / 10)):
data = await self._hass.async_add_executor_job(
pytankerkoenig.getPriceList,
self._api_key,
station_ids[index * 10 : (index + 1) * 10],
)

_LOGGER.debug("Received data: %s", data)
if not data["ok"]:
_LOGGER.error(
"Error fetching data from tankerkoenig.de: %s", data["message"]
)
raise TankerkoenigError(data["message"])
if "prices" not in data:
_LOGGER.error("Did not receive price information from tankerkoenig.de")
raise TankerkoenigError("No prices in data")
else:
_LOGGER.error(
"Error fetching data from tankerkoenig.de: %s", data["message"]
)
raise TankerkoenigError(data["message"])
return data["prices"]
prices.update(data["prices"])
return prices

def add_station(self, station: dict):
"""Add fuel station to the entity list."""
Expand Down
41 changes: 15 additions & 26 deletions homeassistant/components/totalconnect/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
STATE_ALARM_TRIGGERED,
)

from . import DOMAIN as TOTALCONNECT_DOMAIN
from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)

Expand All @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):

alarms = []

client = hass.data[TOTALCONNECT_DOMAIN].client
client = hass.data[DOMAIN].client

for location_id, location in client.locations.items():
location_name = location.location_name
Expand Down Expand Up @@ -71,55 +71,44 @@ def device_state_attributes(self):

def update(self):
"""Return the state of the device."""
status = self._client.get_armed_status(self._location_id)
self._client.get_armed_status(self._location_id)
attr = {
"location_name": self._name,
"location_id": self._location_id,
"ac_loss": self._client.locations[self._location_id].ac_loss,
"low_battery": self._client.locations[self._location_id].low_battery,
"cover_tampered": self._client.locations[
self._location_id
].is_cover_tampered,
].is_cover_tampered(),
"triggered_source": None,
"triggered_zone": None,
}

if status in (self._client.DISARMED, self._client.DISARMED_BYPASS):
if self._client.locations[self._location_id].is_disarmed():
state = STATE_ALARM_DISARMED
elif status in (
self._client.ARMED_STAY,
self._client.ARMED_STAY_INSTANT,
self._client.ARMED_STAY_INSTANT_BYPASS,
):
elif self._client.locations[self._location_id].is_armed_home():
state = STATE_ALARM_ARMED_HOME
elif status == self._client.ARMED_STAY_NIGHT:
elif self._client.locations[self._location_id].is_armed_night():
state = STATE_ALARM_ARMED_NIGHT
elif status in (
self._client.ARMED_AWAY,
self._client.ARMED_AWAY_BYPASS,
self._client.ARMED_AWAY_INSTANT,
self._client.ARMED_AWAY_INSTANT_BYPASS,
):
elif self._client.locations[self._location_id].is_armed_away():
state = STATE_ALARM_ARMED_AWAY
elif status == self._client.ARMED_CUSTOM_BYPASS:
elif self._client.locations[self._location_id].is_armed_custom_bypass():
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
elif status == self._client.ARMING:
elif self._client.locations[self._location_id].is_arming():
state = STATE_ALARM_ARMING
elif status == self._client.DISARMING:
elif self._client.locations[self._location_id].is_disarming():
state = STATE_ALARM_DISARMING
elif status == self._client.ALARMING:
elif self._client.locations[self._location_id].is_triggered_police():
state = STATE_ALARM_TRIGGERED
attr["triggered_source"] = "Police/Medical"
elif status == self._client.ALARMING_FIRE_SMOKE:
elif self._client.locations[self._location_id].is_triggered_fire():
state = STATE_ALARM_TRIGGERED
attr["triggered_source"] = "Fire/Smoke"
elif status == self._client.ALARMING_CARBON_MONOXIDE:
elif self._client.locations[self._location_id].is_triggered_gas():
state = STATE_ALARM_TRIGGERED
attr["triggered_source"] = "Carbon Monoxide"
else:
logging.info(
"Total Connect Client returned unknown status code: %s", status
)
logging.info("Total Connect Client returned unknown status")
state = None

self._state = state
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/totalconnect/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""TotalConnect constants."""

DOMAIN = "totalconnect"
45 changes: 28 additions & 17 deletions homeassistant/components/zha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from homeassistant import config_entries, const as ha_const
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import HomeAssistantType

from . import api
from .core import ZHAGateway
Expand All @@ -27,6 +29,7 @@
DEFAULT_BAUDRATE,
DEFAULT_RADIO_TYPE,
DOMAIN,
SIGNAL_ADD_ENTITIES,
RadioType,
)

Expand Down Expand Up @@ -90,8 +93,15 @@ async def async_setup_entry(hass, config_entry):
"""

zha_data = hass.data.setdefault(DATA_ZHA, {})
zha_data[DATA_ZHA_PLATFORM_LOADED] = {}
config = zha_data.get(DATA_ZHA_CONFIG, {})

zha_data[DATA_ZHA_DISPATCHERS] = []
for component in COMPONENTS:
zha_data[component] = []
coro = hass.config_entries.async_forward_entry_setup(config_entry, component)
zha_data[DATA_ZHA_PLATFORM_LOADED][component] = hass.async_create_task(coro)

if config.get(CONF_ENABLE_QUIRKS, True):
# needs to be done here so that the ZHA module is finished loading
# before zhaquirks is imported
Expand All @@ -100,22 +110,6 @@ async def async_setup_entry(hass, config_entry):
zha_gateway = ZHAGateway(hass, config, config_entry)
await zha_gateway.async_initialize()

zha_data[DATA_ZHA_DISPATCHERS] = []
zha_data[DATA_ZHA_PLATFORM_LOADED] = asyncio.Event()
platforms = []
for component in COMPONENTS:
platforms.append(
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component)
)
)

async def _platforms_loaded():
await asyncio.gather(*platforms)
zha_data[DATA_ZHA_PLATFORM_LOADED].set()

hass.async_create_task(_platforms_loaded())

device_registry = await hass.helpers.device_registry.async_get_registry()
device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
Expand All @@ -134,7 +128,7 @@ async def async_zha_shutdown(event):
await zha_data[DATA_ZHA_GATEWAY].async_update_device_storage()

hass.bus.async_listen_once(ha_const.EVENT_HOMEASSISTANT_STOP, async_zha_shutdown)
hass.async_create_task(zha_gateway.async_load_devices())
hass.async_create_task(async_load_entities(hass, config_entry))
return True


Expand All @@ -152,3 +146,20 @@ async def async_unload_entry(hass, config_entry):
await hass.config_entries.async_forward_entry_unload(config_entry, component)

return True


async def async_load_entities(
hass: HomeAssistantType, config_entry: config_entries.ConfigEntry
) -> None:
"""Load entities after integration was setup."""
await hass.data[DATA_ZHA][DATA_ZHA_GATEWAY].async_prepare_entities()
to_setup = [
hass.data[DATA_ZHA][DATA_ZHA_PLATFORM_LOADED][comp]
for comp in COMPONENTS
if hass.data[DATA_ZHA][comp]
]
results = await asyncio.gather(*to_setup, return_exceptions=True)
for res in results:
if isinstance(res, Exception):
_LOGGER.warning("Couldn't setup zha platform: %s", res)
async_dispatcher_send(hass, SIGNAL_ADD_ENTITIES)
2 changes: 1 addition & 1 deletion homeassistant/components/zha/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation binary sensor from config entry."""
entities_to_create = hass.data[DATA_ZHA][DOMAIN] = []
entities_to_create = hass.data[DATA_ZHA][DOMAIN]

unsub = async_dispatcher_connect(
hass,
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/zha/core/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@
from homeassistant.helpers.typing import HomeAssistantType

from . import const as zha_const, registries as zha_regs, typing as zha_typing
from .. import ( # noqa: F401 pylint: disable=unused-import,
binary_sensor,
cover,
device_tracker,
fan,
light,
lock,
sensor,
switch,
)
from .channels import base

_LOGGER = logging.getLogger(__name__)
Expand Down
27 changes: 16 additions & 11 deletions homeassistant/components/zha/core/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
DATA_ZHA,
DATA_ZHA_BRIDGE_ID,
DATA_ZHA_GATEWAY,
DATA_ZHA_PLATFORM_LOADED,
DEBUG_COMP_BELLOWS,
DEBUG_COMP_ZHA,
DEBUG_COMP_ZIGPY,
Expand Down Expand Up @@ -157,34 +156,40 @@ async def async_initialize(self):
self._hass.data[DATA_ZHA][DATA_ZHA_BRIDGE_ID] = str(
self.application_controller.ieee
)
await self.async_load_devices()
self._initialize_groups()

async def async_load_devices(self) -> None:
"""Restore ZHA devices from zigpy application state."""
await self._hass.data[DATA_ZHA][DATA_ZHA_PLATFORM_LOADED].wait()
zigpy_devices = self.application_controller.devices.values()
for zigpy_device in zigpy_devices:
self._async_get_or_create_device(zigpy_device, restored=True)

async def async_prepare_entities(self) -> None:
"""Prepare entities by initializing device channels."""
semaphore = asyncio.Semaphore(2)

async def _throttle(device: zha_typing.ZigpyDeviceType):
async def _throttle(zha_device: zha_typing.ZhaDeviceType, cached: bool):
async with semaphore:
await self.async_device_restored(device)
await zha_device.async_initialize(from_cache=cached)

zigpy_devices = self.application_controller.devices.values()
_LOGGER.debug("Loading battery powered devices")
await asyncio.gather(
*[
_throttle(dev)
for dev in zigpy_devices
if not dev.node_desc.is_mains_powered
_throttle(dev, cached=True)
for dev in self.devices.values()
if not dev.is_mains_powered
]
)
async_dispatcher_send(self._hass, SIGNAL_ADD_ENTITIES)

_LOGGER.debug("Loading mains powered devices")
await asyncio.gather(
*[_throttle(dev) for dev in zigpy_devices if dev.node_desc.is_mains_powered]
*[
_throttle(dev, cached=False)
for dev in self.devices.values()
if dev.is_mains_powered
]
)
async_dispatcher_send(self._hass, SIGNAL_ADD_ENTITIES)

def device_joined(self, device):
"""Handle device joined.
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zha/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation cover from config entry."""
entities_to_create = hass.data[DATA_ZHA][DOMAIN] = []
entities_to_create = hass.data[DATA_ZHA][DOMAIN]

unsub = async_dispatcher_connect(
hass,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zha/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation device tracker from config entry."""
entities_to_create = hass.data[DATA_ZHA][DOMAIN] = []
entities_to_create = hass.data[DATA_ZHA][DOMAIN]

unsub = async_dispatcher_connect(
hass,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zha/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation fan from config entry."""
entities_to_create = hass.data[DATA_ZHA][DOMAIN] = []
entities_to_create = hass.data[DATA_ZHA][DOMAIN]

unsub = async_dispatcher_connect(
hass,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zha/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation light from config entry."""
entities_to_create = hass.data[DATA_ZHA][light.DOMAIN] = []
entities_to_create = hass.data[DATA_ZHA][light.DOMAIN]

unsub = async_dispatcher_connect(
hass,
Expand Down
Loading