Skip to content

Commit

Permalink
Merge branch 'home-assistant:dev' into verisure_trust
Browse files Browse the repository at this point in the history
  • Loading branch information
niro1987 committed Aug 20, 2023
2 parents accc6e4 + e484066 commit 14a4127
Show file tree
Hide file tree
Showing 185 changed files with 6,548 additions and 1,133 deletions.
5 changes: 5 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ omit =
homeassistant/components/cmus/media_player.py
homeassistant/components/coinbase/sensor.py
homeassistant/components/comed_hourly_pricing/sensor.py
homeassistant/components/comelit/__init__.py
homeassistant/components/comelit/const.py
homeassistant/components/comelit/coordinator.py
homeassistant/components/comelit/light.py
homeassistant/components/comfoconnect/fan.py
homeassistant/components/concord232/alarm_control_panel.py
homeassistant/components/concord232/binary_sensor.py
Expand Down Expand Up @@ -1183,6 +1187,7 @@ omit =
homeassistant/components/starlink/binary_sensor.py
homeassistant/components/starlink/button.py
homeassistant/components/starlink/coordinator.py
homeassistant/components/starlink/device_tracker.py
homeassistant/components/starlink/sensor.py
homeassistant/components/starlink/switch.py
homeassistant/components/starline/__init__.py
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.280
rev: v0.0.285
hooks:
- id: ruff
args:
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ build.json @home-assistant/supervisor
/tests/components/coinbase/ @tombrien
/homeassistant/components/color_extractor/ @GenericStudent
/tests/components/color_extractor/ @GenericStudent
/homeassistant/components/comelit/ @chemelli74
/tests/components/comelit/ @chemelli74
/homeassistant/components/comfoconnect/ @michaelarnauts
/tests/components/comfoconnect/ @michaelarnauts
/homeassistant/components/command_line/ @gjohansson-ST
Expand Down
10 changes: 0 additions & 10 deletions homeassistant/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,6 @@ def get_arguments() -> argparse.Namespace:
return arguments


def cmdline() -> list[str]:
"""Collect path and arguments to re-execute the current hass instance."""
if os.path.basename(sys.argv[0]) == "__main__.py":
modulepath = os.path.dirname(sys.argv[0])
os.environ["PYTHONPATH"] = os.path.dirname(modulepath)
return [sys.executable, "-m", "homeassistant"] + list(sys.argv[1:])

return sys.argv


def check_threads() -> None:
"""Check if there are any lingering threads."""
try:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/ambiclimate/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ async def _get_token_info(self, code):
try:
token_info = await oauth.get_access_token(code)
except ambiclimate.AmbiclimateOauthError:
_LOGGER.error("Failed to get access token", exc_info=True)
_LOGGER.exception("Failed to get access token")
return None

store = Store(self.hass, STORAGE_VERSION, STORAGE_KEY)
Expand Down
22 changes: 22 additions & 0 deletions homeassistant/components/assist_pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ class PipelineEventType(StrEnum):
WAKE_WORD_START = "wake_word-start"
WAKE_WORD_END = "wake_word-end"
STT_START = "stt-start"
STT_VAD_START = "stt-vad-start"
STT_VAD_END = "stt-vad-end"
STT_END = "stt-end"
INTENT_START = "intent-start"
INTENT_END = "intent-end"
Expand Down Expand Up @@ -612,11 +614,31 @@ async def segment_stream(
stream: AsyncIterable[bytes],
) -> AsyncGenerator[bytes, None]:
"""Stop stream when voice command is finished."""
sent_vad_start = False
timestamp_ms = 0
async for chunk in stream:
if not segmenter.process(chunk):
# Silence detected at the end of voice command
self.process_event(
PipelineEvent(
PipelineEventType.STT_VAD_END,
{"timestamp": timestamp_ms},
)
)
break

if segmenter.in_command and (not sent_vad_start):
# Speech detected at start of voice command
self.process_event(
PipelineEvent(
PipelineEventType.STT_VAD_START,
{"timestamp": timestamp_ms},
)
)
sent_vad_start = True

yield chunk
timestamp_ms += (len(chunk) // 2) // 16 # milliseconds @ 16Khz

# Transcribe audio stream
result = await self.stt_provider.async_process_audio_stream(
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bluetooth/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
"bluetooth-adapters==0.16.0",
"bluetooth-auto-recovery==1.2.1",
"bluetooth-data-tools==1.8.0",
"dbus-fast==1.91.2"
"dbus-fast==1.92.0"
]
}
3 changes: 1 addition & 2 deletions homeassistant/components/bluetooth/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,10 @@ async def _async_restart_scanner(self) -> None:
try:
await self._async_start()
except ScannerStartError as ex:
_LOGGER.error(
_LOGGER.exception(
"%s: Failed to restart Bluetooth scanner: %s",
self.name,
ex,
exc_info=True,
)

async def _async_reset_adapter(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ async def write_to_mjpeg_stream(img_bytes: bytes) -> None:
await response.write(
bytes(
"--frameboundary\r\n"
"Content-Type: {}\r\n"
"Content-Length: {}\r\n\r\n".format(content_type, len(img_bytes)),
f"Content-Type: {content_type}\r\n"
f"Content-Length: {len(img_bytes)}\r\n\r\n",
"utf-8",
)
+ img_bytes
Expand Down
34 changes: 34 additions & 0 deletions homeassistant/components/comelit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Comelit integration."""

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PIN, Platform
from homeassistant.core import HomeAssistant

from .const import DOMAIN
from .coordinator import ComelitSerialBridge

PLATFORMS = [Platform.LIGHT]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Comelit platform."""
coordinator = ComelitSerialBridge(hass, entry.data[CONF_HOST], entry.data[CONF_PIN])

await coordinator.async_config_entry_first_refresh()

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
coordinator: ComelitSerialBridge = hass.data[DOMAIN][entry.entry_id]
await coordinator.api.logout()
await coordinator.api.close()
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok
145 changes: 145 additions & 0 deletions homeassistant/components/comelit/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""Config flow for Comelit integration."""
from __future__ import annotations

from collections.abc import Mapping
from typing import Any

from aiocomelit import ComeliteSerialBridgeAPi, exceptions as aiocomelit_exceptions
import voluptuous as vol

from homeassistant import core, exceptions
from homeassistant.config_entries import ConfigEntry, ConfigFlow
from homeassistant.const import CONF_HOST, CONF_PIN
from homeassistant.data_entry_flow import FlowResult

from .const import _LOGGER, DOMAIN

DEFAULT_HOST = "192.168.1.252"
DEFAULT_PIN = "111111"


def user_form_schema(user_input: dict[str, Any] | None) -> vol.Schema:
"""Return user form schema."""
user_input = user_input or {}
return vol.Schema(
{
vol.Optional(CONF_HOST, default=DEFAULT_HOST): str,
vol.Optional(CONF_PIN, default=DEFAULT_PIN): str,
}
)


STEP_REAUTH_DATA_SCHEMA = vol.Schema({vol.Required(CONF_PIN): str})


async def validate_input(
hass: core.HomeAssistant, data: dict[str, Any]
) -> dict[str, str]:
"""Validate the user input allows us to connect."""

api = ComeliteSerialBridgeAPi(data[CONF_HOST], data[CONF_PIN])

try:
await api.login()
except aiocomelit_exceptions.CannotConnect as err:
raise CannotConnect from err
except aiocomelit_exceptions.CannotAuthenticate as err:
raise InvalidAuth from err
finally:
await api.logout()
await api.close()

return {"title": data[CONF_HOST]}


class ComelitConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Comelit."""

VERSION = 1
_reauth_entry: ConfigEntry | None
_reauth_host: str

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
if user_input is None:
return self.async_show_form(
step_id="user", data_schema=user_form_schema(user_input)
)

self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})

errors = {}

try:
info = await validate_input(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
return self.async_create_entry(title=info["title"], data=user_input)

return self.async_show_form(
step_id="user", data_schema=user_form_schema(user_input), errors=errors
)

async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
"""Handle reauth flow."""
self._reauth_entry = self.hass.config_entries.async_get_entry(
self.context["entry_id"]
)
self._reauth_host = entry_data[CONF_HOST]
self.context["title_placeholders"] = {"host": self._reauth_host}
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle reauth confirm."""
assert self._reauth_entry
errors = {}

if user_input is not None:
try:
await validate_input(
self.hass, {CONF_HOST: self._reauth_host} | user_input
)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
self.hass.config_entries.async_update_entry(
self._reauth_entry,
data={
CONF_HOST: self._reauth_host,
CONF_PIN: user_input[CONF_PIN],
},
)
self.hass.async_create_task(
self.hass.config_entries.async_reload(self._reauth_entry.entry_id)
)
return self.async_abort(reason="reauth_successful")

return self.async_show_form(
step_id="reauth_confirm",
description_placeholders={CONF_HOST: self._reauth_entry.data[CONF_HOST]},
data_schema=STEP_REAUTH_DATA_SCHEMA,
errors=errors,
)


class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""


class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
6 changes: 6 additions & 0 deletions homeassistant/components/comelit/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Comelit constants."""
import logging

_LOGGER = logging.getLogger(__package__)

DOMAIN = "comelit"
50 changes: 50 additions & 0 deletions homeassistant/components/comelit/coordinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Support for Comelit."""
import asyncio
from datetime import timedelta
from typing import Any

from aiocomelit import ComeliteSerialBridgeAPi
import aiohttp

from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import _LOGGER, DOMAIN


class ComelitSerialBridge(DataUpdateCoordinator):
"""Queries Comelit Serial Bridge."""

def __init__(self, hass: HomeAssistant, host: str, pin: int) -> None:
"""Initialize the scanner."""

self._host = host
self._pin = pin

self.api = ComeliteSerialBridgeAPi(host, pin)

super().__init__(
hass=hass,
logger=_LOGGER,
name=f"{DOMAIN}-{host}-coordinator",
update_interval=timedelta(seconds=5),
)

async def _async_update_data(self) -> dict[str, Any]:
"""Update router data."""
_LOGGER.debug("Polling Comelit Serial Bridge host: %s", self._host)
try:
logged = await self.api.login()
except (asyncio.exceptions.TimeoutError, aiohttp.ClientConnectorError) as err:
_LOGGER.warning("Connection error for %s", self._host)
raise UpdateFailed(f"Error fetching data: {repr(err)}") from err

if not logged:
raise ConfigEntryAuthFailed

devices_data = await self.api.get_all_devices()
alarm_data = await self.api.get_alarm_config()
await self.api.logout()

return devices_data | alarm_data

0 comments on commit 14a4127

Please sign in to comment.