Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7541e26
Make api_version runtime_data in pi_hole (#148238)
zweckj Jul 8, 2025
bd1917c
Bump pySmartThings to 3.2.7 (#148394)
joostlek Jul 8, 2025
a7cba2b
Handle binary coils with non default mappings in nibe heatpump (#148354)
elupus Jul 8, 2025
8240067
Create own clientsession for lamarzocco (#148385)
zweckj Jul 8, 2025
d2bf271
Bump pylamarzocco to 2.0.11 (#148386)
zweckj Jul 8, 2025
b775ba2
Do not add switch_as_x config entry to source device (#148346)
emontnemery Jul 8, 2025
1a8d4c5
Add tuya snapshot tests for Avatto WT598 thermostat (#148398)
epenet Jul 8, 2025
94862e6
Update Alexa Devices quality scale (#147259)
chemelli74 Jul 8, 2025
1193876
Fix Switchbot cloud plug mini current unit Issue (#148314)
XiaoLing-git Jul 8, 2025
e393929
Matter EVSE StateOfCharge (#148213)
lboue Jul 8, 2025
91b8262
Update strings for Telegram bot (#148409)
hanwg Jul 8, 2025
420d1e1
Fix hassfest command in copilot-instructions (#148405)
abmantis Jul 8, 2025
77ae604
Add tuya snapshot tests for gas leak sensor (#148400)
epenet Jul 8, 2025
8ccd097
Add tuya snapshot tests for bladeless tower fan (#148401)
epenet Jul 8, 2025
546f6af
Bump gios to version 6.1.1 (#148414)
bieniu Jul 8, 2025
ae7bc14
Make the update interval a property of the NextDNS coordinator class …
bieniu Jul 8, 2025
aab8908
Improve entity registry tests related to config entries in devices (#…
emontnemery Jul 8, 2025
c97ad96
Add metadata support to Snapcast media players (#132283)
mill1000 Jul 8, 2025
a35299d
Add preview tests for number and sensor (#148426)
Petro31 Jul 8, 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
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ _LOGGER.debug("Processing data: %s", data) # Use lazy logging
### Validation Commands
```bash
# Check specific integration
python -m script.hassfest --integration my_integration
python -m script.hassfest --integration-path homeassistant/components/my_integration

# Validate quality scale
# Check quality_scale.yaml against current rules
Expand Down
20 changes: 9 additions & 11 deletions homeassistant/components/alexa_devices/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,31 @@ rules:
# Silver
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: todo
docs-installation-parameters: todo
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: done
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: done
test-coverage:
status: todo
comment: all tests missing
test-coverage: done

# Gold
devices: done
diagnostics: todo
diagnostics: done
discovery-update-info:
status: exempt
comment: Network information not relevant
discovery:
status: exempt
comment: There are a ton of mac address ranges in use, but also by kindles which are not supported by this integration
docs-data-update: todo
docs-examples: todo
docs-data-update: done
docs-examples: done
docs-known-limitations: todo
docs-supported-devices: todo
docs-supported-functions: todo
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: todo
docs-use-cases: todo
docs-use-cases: done
dynamic-devices: todo
entity-category: done
entity-device-class: done
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/gios/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["dacite", "gios"],
"requirements": ["gios==6.1.0"]
"requirements": ["gios==6.1.1"]
}
5 changes: 2 additions & 3 deletions homeassistant/components/lamarzocco/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import issue_registry as ir
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.aiohttp_client import async_create_clientsession

from .const import CONF_USE_BLUETOOTH, DOMAIN
from .coordinator import (
Expand Down Expand Up @@ -57,11 +57,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: LaMarzoccoConfigEntry) -
assert entry.unique_id
serial = entry.unique_id

client = async_get_clientsession(hass)
cloud_client = LaMarzoccoCloudClient(
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
client=client,
client=async_create_clientsession(hass),
)

try:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/lamarzocco/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class LaMarzoccoBinarySensorEntityDescription(
WidgetType.CM_BACK_FLUSH, BackFlush(status=BackFlushStatus.OFF)
),
).status
is BackFlushStatus.REQUESTED
in (BackFlushStatus.REQUESTED, BackFlushStatus.CLEANING)
),
entity_category=EntityCategory.DIAGNOSTIC,
supported_fn=lambda coordinator: (
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/lamarzocco/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.selector import (
SelectOptionDict,
SelectSelector,
Expand Down Expand Up @@ -83,7 +83,7 @@ async def async_step_user(
**user_input,
}

self._client = async_get_clientsession(self.hass)
self._client = async_create_clientsession(self.hass)
cloud_client = LaMarzoccoCloudClient(
username=data[CONF_USERNAME],
password=data[CONF_PASSWORD],
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/lamarzocco/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@
"iot_class": "cloud_push",
"loggers": ["pylamarzocco"],
"quality_scale": "platinum",
"requirements": ["pylamarzocco==2.0.10"]
"requirements": ["pylamarzocco==2.0.11"]
}
12 changes: 12 additions & 0 deletions homeassistant/components/matter/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,18 @@ def _update_from_device(self) -> None:
entity_class=MatterSensor,
required_attributes=(clusters.EnergyEvse.Attributes.UserMaximumChargeCurrent,),
),
MatterDiscoverySchema(
platform=Platform.SENSOR,
entity_description=MatterSensorEntityDescription(
key="EnergyEvseStateOfCharge",
translation_key="evse_soc",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
),
entity_class=MatterSensor,
required_attributes=(clusters.EnergyEvse.Attributes.StateOfCharge,),
),
MatterDiscoverySchema(
platform=Platform.SENSOR,
entity_description=MatterSensorEntityDescription(
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/matter/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,9 @@
"other": "Other fault"
}
},
"evse_soc": {
"name": "State of charge"
},
"pump_control_mode": {
"name": "Control mode",
"state": {
Expand Down
26 changes: 10 additions & 16 deletions homeassistant/components/nextdns/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import asyncio
from dataclasses import dataclass
from datetime import timedelta

from aiohttp.client_exceptions import ClientConnectorError
from nextdns import (
Expand Down Expand Up @@ -37,9 +36,6 @@
ATTR_STATUS,
CONF_PROFILE_ID,
DOMAIN,
UPDATE_INTERVAL_ANALYTICS,
UPDATE_INTERVAL_CONNECTION,
UPDATE_INTERVAL_SETTINGS,
)
from .coordinator import (
NextDnsConnectionUpdateCoordinator,
Expand Down Expand Up @@ -69,14 +65,14 @@ class NextDnsData:


PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR, Platform.SWITCH]
COORDINATORS: list[tuple[str, type[NextDnsUpdateCoordinator], timedelta]] = [
(ATTR_CONNECTION, NextDnsConnectionUpdateCoordinator, UPDATE_INTERVAL_CONNECTION),
(ATTR_DNSSEC, NextDnsDnssecUpdateCoordinator, UPDATE_INTERVAL_ANALYTICS),
(ATTR_ENCRYPTION, NextDnsEncryptionUpdateCoordinator, UPDATE_INTERVAL_ANALYTICS),
(ATTR_IP_VERSIONS, NextDnsIpVersionsUpdateCoordinator, UPDATE_INTERVAL_ANALYTICS),
(ATTR_PROTOCOLS, NextDnsProtocolsUpdateCoordinator, UPDATE_INTERVAL_ANALYTICS),
(ATTR_SETTINGS, NextDnsSettingsUpdateCoordinator, UPDATE_INTERVAL_SETTINGS),
(ATTR_STATUS, NextDnsStatusUpdateCoordinator, UPDATE_INTERVAL_ANALYTICS),
COORDINATORS: list[tuple[str, type[NextDnsUpdateCoordinator]]] = [
(ATTR_CONNECTION, NextDnsConnectionUpdateCoordinator),
(ATTR_DNSSEC, NextDnsDnssecUpdateCoordinator),
(ATTR_ENCRYPTION, NextDnsEncryptionUpdateCoordinator),
(ATTR_IP_VERSIONS, NextDnsIpVersionsUpdateCoordinator),
(ATTR_PROTOCOLS, NextDnsProtocolsUpdateCoordinator),
(ATTR_SETTINGS, NextDnsSettingsUpdateCoordinator),
(ATTR_STATUS, NextDnsStatusUpdateCoordinator),
]


Expand Down Expand Up @@ -109,10 +105,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: NextDnsConfigEntry) -> b

# Independent DataUpdateCoordinator is used for each API endpoint to avoid
# unnecessary requests when entities using this endpoint are disabled.
for coordinator_name, coordinator_class, update_interval in COORDINATORS:
coordinator = coordinator_class(
hass, entry, nextdns, profile_id, update_interval
)
for coordinator_name, coordinator_class in COORDINATORS:
coordinator = coordinator_class(hass, entry, nextdns, profile_id)
tasks.append(coordinator.async_config_entry_first_refresh())
coordinators[coordinator_name] = coordinator

Expand Down
25 changes: 22 additions & 3 deletions homeassistant/components/nextdns/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
if TYPE_CHECKING:
from . import NextDnsConfigEntry

from .const import DOMAIN
from .const import (
DOMAIN,
UPDATE_INTERVAL_ANALYTICS,
UPDATE_INTERVAL_CONNECTION,
UPDATE_INTERVAL_SETTINGS,
)

_LOGGER = logging.getLogger(__name__)

Expand All @@ -40,14 +45,14 @@ class NextDnsUpdateCoordinator[CoordinatorDataT: NextDnsData](
"""Class to manage fetching NextDNS data API."""

config_entry: NextDnsConfigEntry
_update_interval: timedelta

def __init__(
self,
hass: HomeAssistant,
config_entry: NextDnsConfigEntry,
nextdns: NextDns,
profile_id: str,
update_interval: timedelta,
) -> None:
"""Initialize."""
self.nextdns = nextdns
Expand All @@ -58,7 +63,7 @@ def __init__(
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=update_interval,
update_interval=self._update_interval,
)

async def _async_update_data(self) -> CoordinatorDataT:
Expand Down Expand Up @@ -93,6 +98,8 @@ async def _async_update_data_internal(self) -> CoordinatorDataT:
class NextDnsStatusUpdateCoordinator(NextDnsUpdateCoordinator[AnalyticsStatus]):
"""Class to manage fetching NextDNS analytics status data from API."""

_update_interval = UPDATE_INTERVAL_ANALYTICS

async def _async_update_data_internal(self) -> AnalyticsStatus:
"""Update data via library."""
return await self.nextdns.get_analytics_status(self.profile_id)
Expand All @@ -101,6 +108,8 @@ async def _async_update_data_internal(self) -> AnalyticsStatus:
class NextDnsDnssecUpdateCoordinator(NextDnsUpdateCoordinator[AnalyticsDnssec]):
"""Class to manage fetching NextDNS analytics Dnssec data from API."""

_update_interval = UPDATE_INTERVAL_ANALYTICS

async def _async_update_data_internal(self) -> AnalyticsDnssec:
"""Update data via library."""
return await self.nextdns.get_analytics_dnssec(self.profile_id)
Expand All @@ -109,6 +118,8 @@ async def _async_update_data_internal(self) -> AnalyticsDnssec:
class NextDnsEncryptionUpdateCoordinator(NextDnsUpdateCoordinator[AnalyticsEncryption]):
"""Class to manage fetching NextDNS analytics encryption data from API."""

_update_interval = UPDATE_INTERVAL_ANALYTICS

async def _async_update_data_internal(self) -> AnalyticsEncryption:
"""Update data via library."""
return await self.nextdns.get_analytics_encryption(self.profile_id)
Expand All @@ -117,6 +128,8 @@ async def _async_update_data_internal(self) -> AnalyticsEncryption:
class NextDnsIpVersionsUpdateCoordinator(NextDnsUpdateCoordinator[AnalyticsIpVersions]):
"""Class to manage fetching NextDNS analytics IP versions data from API."""

_update_interval = UPDATE_INTERVAL_ANALYTICS

async def _async_update_data_internal(self) -> AnalyticsIpVersions:
"""Update data via library."""
return await self.nextdns.get_analytics_ip_versions(self.profile_id)
Expand All @@ -125,6 +138,8 @@ async def _async_update_data_internal(self) -> AnalyticsIpVersions:
class NextDnsProtocolsUpdateCoordinator(NextDnsUpdateCoordinator[AnalyticsProtocols]):
"""Class to manage fetching NextDNS analytics protocols data from API."""

_update_interval = UPDATE_INTERVAL_ANALYTICS

async def _async_update_data_internal(self) -> AnalyticsProtocols:
"""Update data via library."""
return await self.nextdns.get_analytics_protocols(self.profile_id)
Expand All @@ -133,6 +148,8 @@ async def _async_update_data_internal(self) -> AnalyticsProtocols:
class NextDnsSettingsUpdateCoordinator(NextDnsUpdateCoordinator[Settings]):
"""Class to manage fetching NextDNS connection data from API."""

_update_interval = UPDATE_INTERVAL_SETTINGS

async def _async_update_data_internal(self) -> Settings:
"""Update data via library."""
return await self.nextdns.get_settings(self.profile_id)
Expand All @@ -141,6 +158,8 @@ async def _async_update_data_internal(self) -> Settings:
class NextDnsConnectionUpdateCoordinator(NextDnsUpdateCoordinator[ConnectionStatus]):
"""Class to manage fetching NextDNS connection data from API."""

_update_interval = UPDATE_INTERVAL_CONNECTION

async def _async_update_data_internal(self) -> ConnectionStatus:
"""Update data via library."""
return await self.nextdns.connection_status(self.profile_id)
3 changes: 2 additions & 1 deletion homeassistant/components/nibe_heatpump/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class BinarySensor(CoilEntity, BinarySensorEntity):
def __init__(self, coordinator: CoilCoordinator, coil: Coil) -> None:
"""Initialize entity."""
super().__init__(coordinator, coil, ENTITY_ID_FORMAT)
self._on_value = coil.get_mapping_for(1)

def _async_read_coil(self, data: CoilData) -> None:
self._attr_is_on = data.value == "ON"
self._attr_is_on = data.value == self._on_value
8 changes: 5 additions & 3 deletions homeassistant/components/nibe_heatpump/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ class Switch(CoilEntity, SwitchEntity):
def __init__(self, coordinator: CoilCoordinator, coil: Coil) -> None:
"""Initialize entity."""
super().__init__(coordinator, coil, ENTITY_ID_FORMAT)
self._on_value = coil.get_mapping_for(1)
self._off_value = coil.get_mapping_for(0)

def _async_read_coil(self, data: CoilData) -> None:
self._attr_is_on = data.value == "ON"
self._attr_is_on = data.value == self._on_value

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
await self._async_write_coil("ON")
await self._async_write_coil(self._on_value)

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
await self._async_write_coil("OFF")
await self._async_write_coil(self._off_value)
18 changes: 6 additions & 12 deletions homeassistant/components/pi_hole/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_API_KEY,
CONF_API_VERSION,
CONF_HOST,
CONF_LOCATION,
CONF_NAME,
Expand Down Expand Up @@ -52,13 +51,13 @@ class PiHoleData:

api: Hole
coordinator: DataUpdateCoordinator[None]
api_version: int


async def async_setup_entry(hass: HomeAssistant, entry: PiHoleConfigEntry) -> bool:
"""Set up Pi-hole entry."""
name = entry.data[CONF_NAME]
host = entry.data[CONF_HOST]
version = entry.data.get(CONF_API_VERSION)

# remove obsolet CONF_STATISTICS_ONLY from entry.data
if CONF_STATISTICS_ONLY in entry.data:
Expand Down Expand Up @@ -100,15 +99,10 @@ def update_unique_id(

await er.async_migrate_entries(hass, entry.entry_id, update_unique_id)

if version is None:
_LOGGER.debug(
"No API version specified, determining Pi-hole API version for %s", host
)
version = await determine_api_version(hass, dict(entry.data))
_LOGGER.debug("Pi-hole API version determined: %s", version)
hass.config_entries.async_update_entry(
entry, data={**entry.data, CONF_API_VERSION: version}
)
_LOGGER.debug("Determining Pi-hole API version for %s", host)
version = await determine_api_version(hass, dict(entry.data))
_LOGGER.debug("Pi-hole API version determined: %s", version)

# Once API version 5 is deprecated we should instantiate Hole directly
api = api_by_version(hass, dict(entry.data), version)

Expand Down Expand Up @@ -151,7 +145,7 @@ async def async_update_data() -> None:

await coordinator.async_config_entry_first_refresh()

entry.runtime_data = PiHoleData(api, coordinator)
entry.runtime_data = PiHoleData(api, coordinator, version)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

Expand Down
Loading
Loading