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
2 changes: 1 addition & 1 deletion .github/workflows/detect-duplicate-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ jobs:
- name: Detect duplicates using AI
id: ai_detection
if: steps.extract.outputs.should_continue == 'true' && steps.fetch_similar.outputs.has_similar == 'true'
uses: actions/[email protected].3
uses: actions/[email protected].4
with:
model: openai/gpt-4o
system-prompt: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/detect-non-english-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: Detect language using AI
id: ai_language_detection
if: steps.detect_language.outputs.should_continue == 'true'
uses: actions/[email protected].3
uses: actions/[email protected].4
with:
model: openai/gpt-4o-mini
system-prompt: |
Expand Down
7 changes: 2 additions & 5 deletions homeassistant/components/airthings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@

from airthings import Airthings

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import CONF_SECRET
from .coordinator import AirthingsDataUpdateCoordinator
from .coordinator import AirthingsConfigEntry, AirthingsDataUpdateCoordinator

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [Platform.SENSOR]
SCAN_INTERVAL = timedelta(minutes=6)

type AirthingsConfigEntry = ConfigEntry[AirthingsDataUpdateCoordinator]


async def async_setup_entry(hass: HomeAssistant, entry: AirthingsConfigEntry) -> bool:
"""Set up Airthings from a config entry."""
Expand All @@ -31,7 +28,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirthingsConfigEntry) ->
async_get_clientsession(hass),
)

coordinator = AirthingsDataUpdateCoordinator(hass, airthings)
coordinator = AirthingsDataUpdateCoordinator(hass, airthings, entry)

await coordinator.async_config_entry_first_refresh()

Expand Down
11 changes: 10 additions & 1 deletion homeassistant/components/airthings/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from airthings import Airthings, AirthingsDevice, AirthingsError

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

Expand All @@ -13,15 +14,23 @@
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(minutes=6)

type AirthingsConfigEntry = ConfigEntry[AirthingsDataUpdateCoordinator]


class AirthingsDataUpdateCoordinator(DataUpdateCoordinator[dict[str, AirthingsDevice]]):
"""Coordinator for Airthings data updates."""

def __init__(self, hass: HomeAssistant, airthings: Airthings) -> None:
def __init__(
self,
hass: HomeAssistant,
airthings: Airthings,
config_entry: AirthingsConfigEntry,
) -> None:
"""Initialize the coordinator."""
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_method=self._update_method,
update_interval=SCAN_INTERVAL,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/august/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
"documentation": "https://www.home-assistant.io/integrations/august",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==8.10.0", "yalexs-ble==3.1.0"]
"requirements": ["yalexs==8.10.0", "yalexs-ble==3.1.2"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/bluetooth/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"bluetooth-adapters==2.0.0",
"bluetooth-auto-recovery==1.5.2",
"bluetooth-data-tools==1.28.2",
"dbus-fast==2.44.2",
"dbus-fast==2.44.3",
"habluetooth==4.0.1"
]
}
2 changes: 1 addition & 1 deletion homeassistant/components/dhcp/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"quality_scale": "internal",
"requirements": [
"aiodhcpwatcher==1.2.0",
"aiodiscover==2.7.0",
"aiodiscover==2.7.1",
"cached-ipaddress==0.10.0"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/husqvarna_automower_ble",
"iot_class": "local_polling",
"requirements": ["automower-ble==0.2.1"]
"requirements": ["automower-ble==0.2.7"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/media_extractor/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"iot_class": "calculated",
"loggers": ["yt_dlp"],
"quality_scale": "internal",
"requirements": ["yt-dlp[default]==2025.06.09"],
"requirements": ["yt-dlp[default]==2025.07.21"],
"single_config_entry": true
}
1 change: 1 addition & 0 deletions homeassistant/components/thread/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

KNOWN_BRANDS: dict[str | None, str] = {
"Amazon": "amazon",
"Apple": "apple",
"Apple Inc.": "apple",
"Aqara": "aqara_gateway",
"eero": "eero",
Expand Down
16 changes: 15 additions & 1 deletion homeassistant/components/tuya/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,22 @@ def from_json(cls, dpcode: DPCode, data: str) -> EnumTypeData | None:
return cls(dpcode, **parsed)


class ComplexTypeData:
"""Complex Type Data (for JSON/RAW parsing)."""

@classmethod
def from_json(cls, data: str) -> Self:
"""Load JSON string and return a ComplexTypeData object."""
raise NotImplementedError("from_json is not implemented for this type")

@classmethod
def from_raw(cls, data: str) -> Self:
"""Decode base64 string and return a ComplexTypeData object."""
raise NotImplementedError("from_raw is not implemented for this type")


@dataclass
class ElectricityTypeData:
class ElectricityTypeData(ComplexTypeData):
"""Electricity Type Data."""

electriccurrent: str | None = None
Expand Down
38 changes: 32 additions & 6 deletions homeassistant/components/tuya/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@
UnitOfMeasurement,
)
from .entity import TuyaEntity
from .models import ElectricityTypeData, EnumTypeData, IntegerTypeData
from .models import ComplexTypeData, ElectricityTypeData, EnumTypeData, IntegerTypeData


@dataclass(frozen=True)
class TuyaSensorEntityDescription(SensorEntityDescription):
"""Describes Tuya sensor entity."""

complex_type: type[ComplexTypeData] | None = None
subkey: str | None = None


Expand Down Expand Up @@ -368,6 +369,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -376,6 +378,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -384,6 +387,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
TuyaSensorEntityDescription(
Expand All @@ -392,6 +396,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -400,6 +405,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -408,6 +414,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
TuyaSensorEntityDescription(
Expand All @@ -416,6 +423,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -424,6 +432,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -432,6 +441,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
TuyaSensorEntityDescription(
Expand Down Expand Up @@ -1247,6 +1257,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
translation_key="total_power",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -1255,6 +1266,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -1263,6 +1275,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -1271,6 +1284,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
TuyaSensorEntityDescription(
Expand All @@ -1279,6 +1293,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -1287,6 +1302,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -1295,6 +1311,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
TuyaSensorEntityDescription(
Expand All @@ -1303,6 +1320,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
complex_type=ElectricityTypeData,
subkey="electriccurrent",
),
TuyaSensorEntityDescription(
Expand All @@ -1311,6 +1329,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
Expand All @@ -1319,6 +1338,7 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
complex_type=ElectricityTypeData,
subkey="voltage",
),
),
Expand Down Expand Up @@ -1417,7 +1437,7 @@ class TuyaSensorEntity(TuyaEntity, SensorEntity):

_status_range: DeviceStatusRange | None = None
_type: DPType | None = None
_type_data: IntegerTypeData | EnumTypeData | None = None
_type_data: IntegerTypeData | EnumTypeData | ComplexTypeData | None = None
_uom: UnitOfMeasurement | None = None

def __init__(
Expand Down Expand Up @@ -1516,15 +1536,21 @@ def native_value(self) -> StateType:

# Get subkey value from Json string.
if self._type is DPType.JSON:
if self.entity_description.subkey is None:
if (
self.entity_description.complex_type is None
or self.entity_description.subkey is None
):
return None
values = ElectricityTypeData.from_json(value)
values = self.entity_description.complex_type.from_json(value)
return getattr(values, self.entity_description.subkey)

if self._type is DPType.RAW:
if self.entity_description.subkey is None:
if (
self.entity_description.complex_type is None
or self.entity_description.subkey is None
):
return None
values = ElectricityTypeData.from_raw(value)
values = self.entity_description.complex_type.from_raw(value)
return getattr(values, self.entity_description.subkey)

# Valid string or enum value
Expand Down
14 changes: 9 additions & 5 deletions homeassistant/components/volvo/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
"default": "mdi:gas-station"
},
"charger_connection_status": {
"default": "mdi:ev-plug-ccs2"
"default": "mdi:power-plug-off",
"state": {
"connected": "mdi:power-plug",
"fault": "mdi:flash-alert"
}
},
"charging_power": {
"default": "mdi:gauge-empty",
Expand All @@ -44,22 +48,22 @@
}
},
"distance_to_empty_battery": {
"default": "mdi:gauge-empty"
"default": "mdi:battery-outline"
},
"distance_to_empty_tank": {
"default": "mdi:gauge-empty"
},
"distance_to_service": {
"default": "mdi:wrench-clock"
"default": "mdi:wrench-check"
},
"engine_time_to_service": {
"default": "mdi:wrench-clock"
"default": "mdi:wrench-cog"
},
"estimated_charging_time": {
"default": "mdi:battery-clock"
},
"fuel_amount": {
"default": "mdi:gas-station"
"default": "mdi:fuel"
},
"odometer": {
"default": "mdi:counter"
Expand Down
Loading
Loading