Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
41ab7b3
Set timeout for remote calendar (#147024)
Thomas55555 Jul 3, 2025
9a49595
Fix missing port in samsungtv (#147962)
epenet Jul 3, 2025
0f32b63
Bump ZHA to 0.0.62 (#147966)
puddly Jul 2, 2025
a2ffe32
Bump aiounifi to v84 (#147987)
Kane610 Jul 2, 2025
c23bfb1
Fix state being incorrectly reported in some situations on Music Assi…
marcelveldt Jul 3, 2025
f806e6b
Bump hass-nabucasa from 0.104.0 to 0.105.0 (#148040)
ludeeus Jul 3, 2025
898ef43
Fix Telegram bots using plain text parser failing to load on restart …
hanwg Jul 4, 2025
f42e7d9
Bump pyenphase to 2.2.0 (#148070)
catsmanac Jul 3, 2025
eb58c10
Cancel enphase mac verification on unload. (#148072)
catsmanac Jul 3, 2025
342b4c3
Bump aioamazondevices to 3.2.3 (#148082)
chemelli74 Jul 4, 2025
c646658
Update frontend to 20250702.1 (#148131)
bramkragten Jul 4, 2025
3ffec2a
[ci] Fix typing issue with aiohttp and aiosignal (#148141)
cdce8p Jul 4, 2025
4e163c4
Bump venstarcolortouch to 0.21 (#148152)
mlfreeman2 Jul 4, 2025
a274961
Bump version to 2025.7.1
frenck Jul 4, 2025
5d6b02f
2025.7.1 (#148171)
frenck Jul 4, 2025
2b7992e
Squeezebox: Fix track selection in media browser (#147185)
Hypfer Jul 5, 2025
9077965
Squeezebox: Fix tracks not having thumbnails (#147187)
Hypfer Jul 5, 2025
c965da6
Bump pysmlight to v0.2.7 (#148101)
tl-sl Jul 4, 2025
9650727
Fix REST sensor charset handling to respect Content-Type header (#148…
bdraco Jul 7, 2025
74f9549
Fix UTF-8 encoding for REST basic authentication (#148225)
bdraco Jul 6, 2025
f4ca560
Bump pylamarzocco to 2.0.10 (#148233)
zweckj Jul 5, 2025
b4d789f
Bump sharkiq to 1.1.1 (#148244)
funkybunch Jul 7, 2025
59bcf11
bump motionblinds to 0.6.29 (#148265)
starkillerOG Jul 6, 2025
5c3b279
Bump aiowebostv to 0.7.4 (#148273)
thecode Jul 7, 2025
3d3f252
Bump `gios` to version 6.1.0 (#148274)
bieniu Jul 7, 2025
672ffa5
Restore httpx compatibility for non-primitive REST query parameters (…
bdraco Jul 7, 2025
4a10370
Bump pyenphase to 2.2.1 (#148292)
catsmanac Jul 7, 2025
14f059c
Add lamp states to smartthings selector (#148302)
jvits227 Jul 12, 2025
d303a7d
Fix Switchbot cloud plug mini current unit Issue (#148314)
XiaoLing-git Jul 8, 2025
186c4e7
Bump pyswitchbot to 0.68.1 (#148335)
zerzhang Jul 7, 2025
2377b13
Handle binary coils with non default mappings in nibe heatpump (#148354)
elupus Jul 8, 2025
91cdf1a
Bump aioamazondevices to 3.2.8 (#148365)
chemelli74 Jul 8, 2025
3b04785
Create own clientsession for lamarzocco (#148385)
zweckj Jul 8, 2025
435465e
Bump pylamarzocco to 2.0.11 (#148386)
zweckj Jul 8, 2025
d51a44a
Bump pySmartThings to 3.2.7 (#148394)
joostlek Jul 8, 2025
b8425de
Bump uiprotect to version 7.14.2 (#148453)
RaHehl Jul 9, 2025
b6d316c
Bump hass-nabucasa from 0.105.0 to 0.106.0 (#148473)
ludeeus Jul 9, 2025
00e2a17
Revert "Deprecate hddtemp" (#148482)
edenhaus Jul 9, 2025
e951fc4
Fix entity_id should be based on object_id the first time an entity i…
jbouwh Jul 11, 2025
9c9836d
Bump aioimmich to 0.10.2 (#148503)
mib1185 Jul 9, 2025
962ad99
Add workaround for sub units without main device in AVM Fritz!SmartHo…
mib1185 Jul 9, 2025
0990cef
Add Home Connect resume command button when an appliance is paused (#…
Diegorro98 Jul 9, 2025
d87379d
Use the link to the issue instead of creating new issues at Home Conn…
Diegorro98 Jul 10, 2025
63b21fd
Ensure response is fully read to prevent premature connection closure…
jpbede Jul 11, 2025
5cf5be8
Fix for Renson set Breeze fan speed (#148537)
krmarien Jul 10, 2025
3c2fa02
Remove vg argument from miele auth flow (#148541)
astrandb Jul 10, 2025
f1272ef
Bump aiohttp to 3.12.14 (#148565)
bdraco Jul 10, 2025
dc27365
Update frontend to 20250702.2 (#148573)
bramkragten Jul 10, 2025
150d471
Fix Google Cloud 504 Deadline Exceeded (#148589)
luuquangvu Jul 11, 2025
80c52ad
Fix - only enable AlexaModeController if at least one mode is offered…
jbouwh Jul 14, 2025
649fbfc
snoo: use correct value for right safety clip binary sensor (#148647)
falconindy Jul 12, 2025
c802430
Bump nyt_games to 0.5.0 (#148654)
hexEF Jul 12, 2025
c4ddcd6
Fix Charge Cable binary sensor in Teslemetry (#148675)
Bre77 Jul 14, 2025
d4374db
Bump PyViCare to 2.50.0 (#148679)
CFenner Jul 14, 2025
f767298
Fix hide empty sections in mqtt subentry flows (#148692)
jbouwh Jul 14, 2025
80384b8
Bump aioshelly to 13.7.2 (#148706)
thecode Jul 13, 2025
691a0ca
Bump aioamazondevices to 3.2.10 (#148709)
chemelli74 Jul 13, 2025
87af9fc
Bump version to 2025.7.2
frenck Jul 14, 2025
1f59b73
2025.7.2 (#148725)
frenck Jul 14, 2025
c6d0aad
Handle connection issues after websocket reconnected in homematicip_c…
hahn-th Jul 15, 2025
caf0492
Fix Shelly `n_current` sensor removal condition (#148740)
bieniu Jul 14, 2025
56e0aa1
Bump pySmartThings to 3.2.8 (#148761)
joostlek Jul 14, 2025
69fdc1d
Bump Tesla Fleet API to 1.2.2 (#148776)
Bre77 Jul 15, 2025
9e4b8df
Use ffmpeg for generic cameras in go2rtc (#148818)
edenhaus Jul 15, 2025
8e0a89d
Add guard to prevent exception in Sonos Favorites (#148854)
PeteRager Jul 16, 2025
1644484
Fix button platform parent class in Teslemetry (#148863)
Bre77 Jul 16, 2025
11a2c73
Bump pyenphase to 2.2.2 (#148870)
catsmanac Jul 16, 2025
7a3eb53
Bump gios to version 6.1.1 (#148414)
bieniu Jul 8, 2025
b6edcc9
Bump `gios` to version 6.1.2 (#148884)
bieniu Jul 16, 2025
5656b4c
Bump async-upnp-client to 0.45.0 (#148961)
StevenLooman Jul 17, 2025
8fdc50a
Pass Syncthru entry to coordinator (#148974)
joostlek Jul 17, 2025
68889e1
Update frontend to 20250702.3 (#148994)
bramkragten Jul 18, 2025
d57c5ff
Bump PySwitchbot to 0.68.2 (#148996)
bdraco Jul 18, 2025
c6bb26b
Ignore MQTT sensor unit of measurement if it is an empty string (#149…
jbouwh Jul 18, 2025
190c98f
Bump aioamazondevices to 3.5.0 (#149011)
chemelli74 Jul 18, 2025
0675e34
Bump version to 2025.7.3
frenck Jul 18, 2025
456f992
2025.7.3 (#149024)
bramkragten Jul 22, 2025
5b08724
Keep entities of dead Z-Wave devices available (#148611)
AlCalzone Jul 11, 2025
254ccca
Fix warning about failure to get action during setup phase (#148923)
mback2k Jul 23, 2025
959c3a8
Fix a bug in rainbird device migration that results in additional dev…
allenporter Jul 19, 2025
fa20786
Fix multiple webhook secrets for Telegram bot (#149103)
hanwg Jul 22, 2025
f428ffd
Bump pyschlage to 2025.7.2 (#149148)
dknowles2 Jul 21, 2025
c3eb6de
Fix Matter light get brightness (#149186)
jvmahon Jul 25, 2025
68b7d09
Fix brightness_step and brightness_step_pct via lifx.set_state (#149217)
Djelibeybi Jul 23, 2025
60f4d29
Add Z-Wave USB migration confirm step (#149243)
MartinHjelmare Jul 22, 2025
4c8ab8e
Add fan off mode to the supported fan modes to fujitsu_fglair (#149277)
crevetor Jul 23, 2025
cd800da
Update Tesla OAuth Server in Tesla Fleet (#149280)
Bre77 Jul 23, 2025
4a7d06a
Update slixmpp to 1.10.0 (#149374)
gaaf Jul 27, 2025
dc6d2e3
Bump aioamazondevices to 3.5.1 (#149385)
chemelli74 Jul 24, 2025
725799c
Bump pysuezV2 to 2.0.7 (#149436)
jb101010-2 Jul 26, 2025
f0cb5d5
Bump habiticalib to v0.4.1 (#149523)
tr4nt0r Jul 27, 2025
d384bee
Bump version to 2025.7.4
frenck Jul 27, 2025
777b312
2025.7.4 (#149526)
frenck Jul 28, 2025
09e7d8d
Increase open file descriptor limit on startup (#148940)
agners Jul 29, 2025
25407c0
Bump aiohttp to 3.12.15 (#149609)
bdraco Jul 29, 2025
b67e85e
Introduce Ubiquiti UISP airOS (#148989)
CoMPaTech Jul 29, 2025
aaec243
Properly cleanup ONVIF events to prevent log flooding on setup errors…
bdraco Jul 29, 2025
9f45801
Remove advanced mode from group `all` option. (#149626)
karwosts Jul 29, 2025
7e2fd6e
Merge branch 'master' into dev
frenck Jul 29, 2025
c4c4463
Update IQS for Alexa Devices (#149639)
chemelli74 Jul 29, 2025
62713b1
Update pyblu to 2.0.4 (#149589)
cdce8p Jul 29, 2025
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
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ homeassistant.components.air_quality.*
homeassistant.components.airgradient.*
homeassistant.components.airly.*
homeassistant.components.airnow.*
homeassistant.components.airos.*
homeassistant.components.airq.*
homeassistant.components.airthings.*
homeassistant.components.airthings_ble.*
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion homeassistant/brands/ubiquiti.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"domain": "ubiquiti",
"name": "Ubiquiti",
"integrations": ["unifi", "unifi_direct", "unifiled", "unifiprotect"]
"integrations": ["airos", "unifi", "unifi_direct", "unifiled", "unifiprotect"]
}
42 changes: 42 additions & 0 deletions homeassistant/components/airos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""The Ubiquiti airOS integration."""

from __future__ import annotations

from airos.airos8 import AirOS

from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .coordinator import AirOSConfigEntry, AirOSDataUpdateCoordinator

_PLATFORMS: list[Platform] = [Platform.SENSOR]


async def async_setup_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> bool:
"""Set up Ubiquiti airOS from a config entry."""

# By default airOS 8 comes with self-signed SSL certificates,
# with no option in the web UI to change or upload a custom certificate.
session = async_get_clientsession(hass, verify_ssl=False)

airos_device = AirOS(
host=entry.data[CONF_HOST],
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
session=session,
)

coordinator = AirOSDataUpdateCoordinator(hass, entry, airos_device)
await coordinator.async_config_entry_first_refresh()

entry.runtime_data = coordinator

await hass.config_entries.async_forward_entry_setups(entry, _PLATFORMS)

return True


async def async_unload_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, _PLATFORMS)
82 changes: 82 additions & 0 deletions homeassistant/components/airos/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Config flow for the Ubiquiti airOS integration."""

from __future__ import annotations

import logging
from typing import Any

from airos.exceptions import (
ConnectionAuthenticationError,
ConnectionSetupError,
DataMissingError,
DeviceConnectionError,
KeyDataMissingError,
)
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import DOMAIN
from .coordinator import AirOS

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_USERNAME, default="ubnt"): str,
vol.Required(CONF_PASSWORD): str,
}
)


class AirOSConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Ubiquiti airOS."""

VERSION = 1

async def async_step_user(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle the initial step."""
errors: dict[str, str] = {}
if user_input is not None:
# By default airOS 8 comes with self-signed SSL certificates,
# with no option in the web UI to change or upload a custom certificate.
session = async_get_clientsession(self.hass, verify_ssl=False)

airos_device = AirOS(
host=user_input[CONF_HOST],
username=user_input[CONF_USERNAME],
password=user_input[CONF_PASSWORD],
session=session,
)
try:
await airos_device.login()
airos_data = await airos_device.status()

except (
ConnectionSetupError,
DeviceConnectionError,
):
errors["base"] = "cannot_connect"
except (ConnectionAuthenticationError, DataMissingError):
errors["base"] = "invalid_auth"
except KeyDataMissingError:
errors["base"] = "key_data_missing"
except Exception:
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(airos_data.derived.mac)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=airos_data.host.hostname, data=user_input
)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)
9 changes: 9 additions & 0 deletions homeassistant/components/airos/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Constants for the Ubiquiti airOS integration."""

from datetime import timedelta

DOMAIN = "airos"

SCAN_INTERVAL = timedelta(minutes=1)

MANUFACTURER = "Ubiquiti"
66 changes: 66 additions & 0 deletions homeassistant/components/airos/coordinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""DataUpdateCoordinator for AirOS."""

from __future__ import annotations

import logging

from airos.airos8 import AirOS, AirOSData
from airos.exceptions import (
ConnectionAuthenticationError,
ConnectionSetupError,
DataMissingError,
DeviceConnectionError,
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryError
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DOMAIN, SCAN_INTERVAL

_LOGGER = logging.getLogger(__name__)

type AirOSConfigEntry = ConfigEntry[AirOSDataUpdateCoordinator]


class AirOSDataUpdateCoordinator(DataUpdateCoordinator[AirOSData]):
"""Class to manage fetching AirOS data from single endpoint."""

config_entry: AirOSConfigEntry

def __init__(
self, hass: HomeAssistant, config_entry: AirOSConfigEntry, airos_device: AirOS
) -> None:
"""Initialize the coordinator."""
self.airos_device = airos_device
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
)

async def _async_update_data(self) -> AirOSData:
"""Fetch data from AirOS."""
try:
await self.airos_device.login()
return await self.airos_device.status()
except (ConnectionAuthenticationError,) as err:
_LOGGER.exception("Error authenticating with airOS device")
raise ConfigEntryError(
translation_domain=DOMAIN, translation_key="invalid_auth"
) from err
except (ConnectionSetupError, DeviceConnectionError, TimeoutError) as err:
_LOGGER.error("Error connecting to airOS device: %s", err)
raise UpdateFailed(
translation_domain=DOMAIN,
translation_key="cannot_connect",
) from err
except (DataMissingError,) as err:
_LOGGER.error("Expected data not returned by airOS device: %s", err)
raise UpdateFailed(
translation_domain=DOMAIN,
translation_key="error_data_missing",
) from err
36 changes: 36 additions & 0 deletions homeassistant/components/airos/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Generic AirOS Entity Class."""

from __future__ import annotations

from homeassistant.const import CONF_HOST
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN, MANUFACTURER
from .coordinator import AirOSDataUpdateCoordinator


class AirOSEntity(CoordinatorEntity[AirOSDataUpdateCoordinator]):
"""Represent a AirOS Entity."""

_attr_has_entity_name = True

def __init__(self, coordinator: AirOSDataUpdateCoordinator) -> None:
"""Initialise the gateway."""
super().__init__(coordinator)

airos_data = self.coordinator.data

configuration_url: str | None = (
f"https://{coordinator.config_entry.data[CONF_HOST]}"
)

self._attr_device_info = DeviceInfo(
connections={(CONNECTION_NETWORK_MAC, airos_data.derived.mac)},
configuration_url=configuration_url,
identifiers={(DOMAIN, str(airos_data.host.device_id))},
manufacturer=MANUFACTURER,
model=airos_data.host.devmodel,
name=airos_data.host.hostname,
sw_version=airos_data.host.fwversion,
)
10 changes: 10 additions & 0 deletions homeassistant/components/airos/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"domain": "airos",
"name": "Ubiquiti airOS",
"codeowners": ["@CoMPaTech"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airos",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["airos==0.2.1"]
}
72 changes: 72 additions & 0 deletions homeassistant/components/airos/quality_scale.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
rules:
# Bronze
action-setup:
status: exempt
comment: airOS does not have actions
appropriate-polling: done
brands: done
common-modules: done
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions:
status: exempt
comment: airOS does not have actions
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: done
entity-event-setup:
status: exempt
comment: local_polling without events
entity-unique-id: done
has-entity-name: done
runtime-data: done
test-before-configure: done
test-before-setup: done
unique-config-entry: done

# Silver
action-exceptions:
status: exempt
comment: airOS does not have actions
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: todo
integration-owner: done
log-when-unavailable: todo
parallel-updates: todo
reauthentication-flow: todo
test-coverage: done

# Gold
devices: done
diagnostics: todo
discovery-update-info: todo
discovery: todo
docs-data-update: done
docs-examples: todo
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: todo
docs-troubleshooting: done
docs-use-cases: todo
dynamic-devices: todo
entity-category: done
entity-device-class: done
entity-disabled-by-default:
status: todo
comment: prepared binary_sensors will provide this
entity-translations: done
exception-translations: done
icon-translations:
status: exempt
comment: no (custom) icons used or envisioned
reconfiguration-flow: todo
repair-issues: todo
stale-devices: todo

# Platinum
async-dependency: done
inject-websession: done
strict-typing: done
Loading
Loading