Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ on:

env:
BUILD_TYPE: core
DEFAULT_PYTHON: "3.13"
DEFAULT_PYTHON: "3.14.2"
PIP_TIMEOUT: 60
UV_HTTP_TIMEOUT: 60
UV_SYSTEM_PYTHON: "true"
# Base image version from https://github.com/home-assistant/docker
BASE_IMAGE_VERSION: "2025.12.0"
BASE_IMAGE_VERSION: "2026.01.0"
ARCHITECTURES: '["amd64", "aarch64"]'

jobs:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ env:
CACHE_VERSION: 2
UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 1
HA_SHORT_VERSION: "2026.2"
DEFAULT_PYTHON: "3.13.11"
ALL_PYTHON_VERSIONS: "['3.13.11', '3.14.2']"
HA_SHORT_VERSION: "2026.3"
DEFAULT_PYTHON: "3.14.2"
ALL_PYTHON_VERSIONS: "['3.14.2']"
# 10.3 is the oldest supported version
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
# 10.6 is the current long-term-support
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/translations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- "**strings.json"

env:
DEFAULT_PYTHON: "3.13"
DEFAULT_PYTHON: "3.14.2"

jobs:
upload:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ on:
- "script/gen_requirements_all.py"

env:
DEFAULT_PYTHON: "3.13"
DEFAULT_PYTHON: "3.14.2"

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name}}
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13
3.14
2 changes: 1 addition & 1 deletion homeassistant/components/conversation/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/conversation",
"integration_type": "entity",
"quality_scale": "internal",
"requirements": ["hassil==3.5.0", "home-assistant-intents==2026.1.6"]
"requirements": ["hassil==3.5.0", "home-assistant-intents==2026.1.28"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/dlink/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from datetime import datetime
import logging
import urllib
import urllib.error

from pyW215.pyW215 import SmartPlug

Expand Down
9 changes: 8 additions & 1 deletion homeassistant/components/eafm/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,20 @@ async def async_step_user(
self.stations = {}
for station in stations:
label = station["label"]
rloId = station["RLOIid"]

# API annoyingly sometimes returns a list and some times returns a string
# E.g. L3121 has a label of ['Scurf Dyke', 'Scurf Dyke Dyke Level']
if isinstance(label, list):
label = label[-1]

self.stations[label] = station["stationReference"]
# Similar for RLOIid
# E.g. 0018 has an RLOIid of ['10427', '9154']
if isinstance(rloId, list):
rloId = rloId[-1]

fullName = label + " - " + rloId
self.stations[fullName] = station["stationReference"]

if not self.stations:
return self.async_abort(reason="no_stations")
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/hdfury/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"documentation": "https://www.home-assistant.io/integrations/hdfury",
"integration_type": "device",
"iot_class": "local_polling",
"quality_scale": "silver",
"quality_scale": "gold",
"requirements": ["hdfury==1.4.2"],
"zeroconf": [
{ "name": "diva-*", "type": "_http._tcp.local." },
Expand Down
14 changes: 8 additions & 6 deletions homeassistant/components/hdfury/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,26 @@ rules:
diagnostics: done
discovery-update-info: done
discovery: done
docs-data-update: todo
docs-examples: todo
docs-known-limitations: todo
docs-data-update: done
docs-examples: done
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: todo
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices:
status: exempt
comment: Device type integration.
entity-category: done
entity-device-class: done
entity-disabled-by-default: todo
entity-disabled-by-default: done
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: done
repair-issues: todo
repair-issues:
status: exempt
comment: The integration doesn't have any repair cases.
stale-devices:
status: exempt
comment: Device type integration.
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/namecheapdns/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
"user": {
"data": {
"domain": "[%key:common::config_flow::data::username%]",
"domain": "Domain",
"host": "[%key:common::config_flow::data::host%]",
"password": "Dynamic DNS password"
},
Expand Down
6 changes: 1 addition & 5 deletions homeassistant/components/prometheus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,7 @@ def handle_device_registry_updated(
if event.data["action"] != "update" or "area_id" not in event.data["changes"]:
return

device_id = event.data.get("device_id")

if device_id is None:
return

device_id = event.data["device_id"]
_LOGGER.debug("Handling device update for %s", device_id)

device = self.device_registry.async_get(device_id)
Expand Down
16 changes: 4 additions & 12 deletions homeassistant/components/recorder/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from collections.abc import Callable
from concurrent.futures.thread import _threads_queues, _worker
import sys
import threading
from typing import Any
import weakref
Expand Down Expand Up @@ -54,17 +53,10 @@ def weakref_cb( # type: ignore[no-untyped-def]
) -> None:
q.put(None)

if sys.version_info >= (3, 14):
additional_args = (
self._create_worker_context(),
self._work_queue,
)
else:
additional_args = (
self._work_queue,
self._initializer,
self._initargs,
)
additional_args = (
self._create_worker_context(),
self._work_queue,
)

num_threads = len(self._threads)
if num_threads < self._max_workers:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/shelly/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ async def get_coap_context(hass: HomeAssistant) -> COAP:
ipv4: list[IPv4Address] = []
if not network.async_only_default_interface_enabled(adapters):
ipv4.extend(
address
cast(IPv4Address, address)
for address in await network.async_get_enabled_source_ips(hass)
if address.version == 4
and not (
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/components/ssdp/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

from ipaddress import IPv4Address, IPv6Address
from typing import cast

from homeassistant.components import network
from homeassistant.core import HomeAssistant
Expand All @@ -15,5 +16,8 @@ async def async_build_source_set(hass: HomeAssistant) -> set[IPv4Address | IPv6A
for source_ip in await network.async_get_enabled_source_ips(hass)
if not source_ip.is_loopback
and not source_ip.is_global
and ((source_ip.version == 6 and source_ip.scope_id) or source_ip.version == 4)
and (
(source_ip.version == 6 and cast(IPv6Address, source_ip).scope_id)
or source_ip.version == 4
)
}
5 changes: 3 additions & 2 deletions homeassistant/components/ssdp/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from collections.abc import Callable, Coroutine, Mapping
from datetime import timedelta
from enum import Enum
from ipaddress import IPv4Address
from ipaddress import IPv4Address, IPv6Address
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, cast

from async_upnp_client.aiohttp import AiohttpSessionRequester
from async_upnp_client.const import AddressTupleVXType, DeviceOrServiceType, SsdpSource
Expand Down Expand Up @@ -260,6 +260,7 @@ async def _async_start_ssdp_listeners(self) -> None:
for source_ip in await async_build_source_set(self.hass):
source_ip_str = str(source_ip)
if source_ip.version == 6:
source_ip = cast(IPv6Address, source_ip)
assert source_ip.scope_id is not None
source_tuple: AddressTupleVXType = (
source_ip_str,
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/ssdp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

import asyncio
from contextlib import ExitStack
from ipaddress import IPv6Address
import logging
import socket
from time import time
from typing import Any
from typing import Any, cast
from urllib.parse import urljoin
import xml.etree.ElementTree as ET

Expand Down Expand Up @@ -171,6 +172,7 @@ async def _async_start_upnp_servers(self, event: Event) -> None:
for source_ip in await async_build_source_set(self.hass):
source_ip_str = str(source_ip)
if source_ip.version == 6:
source_ip = cast(IPv6Address, source_ip)
assert source_ip.scope_id is not None
source_tuple: AddressTupleVXType = (
source_ip_str,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/template/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def number(
attribute: str,
minimum: float | None = None,
maximum: float | None = None,
return_type: type[float] | type[int] = float,
return_type: type[float | int] = float,
**kwargs: Any,
) -> Callable[[Any], float | int | None]:
"""Convert the result to a number (float or int).
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/tessie/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@
"charge_state_charging_state": {
"default": "mdi:ev-station"
},
"charge_state_energy_remaining": {
"default": "mdi:battery-medium"
},
"charge_state_minutes_to_full_charge": {
"default": "mdi:clock-end"
},
Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/tessie/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ class TessieSensorEntityDescription(SensorEntityDescription):
suggested_display_precision=1,
entity_registry_enabled_default=False,
),
TessieSensorEntityDescription(
key="charge_state_energy_remaining",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY_STORAGE,
entity_category=EntityCategory.DIAGNOSTIC,
suggested_display_precision=2,
),
TessieSensorEntityDescription(
key="drive_state_speed",
state_class=SensorStateClass.MEASUREMENT,
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/tessie/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@
"stopped": "[%key:common::state::stopped%]"
}
},
"charge_state_energy_remaining": {
"name": "Energy remaining"
},
"charge_state_est_battery_range": {
"name": "Battery range estimate"
},
Expand Down
Loading
Loading