Skip to content

[pull] dev from home-assistant:dev #661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 5, 2025
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: 2 additions & 0 deletions homeassistant/components/backup/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class BackupCoordinatorData:
"""Class to hold backup data."""

backup_manager_state: BackupManagerState
last_attempted_automatic_backup: datetime | None
last_successful_automatic_backup: datetime | None
next_scheduled_automatic_backup: datetime | None

Expand Down Expand Up @@ -70,6 +71,7 @@ async def _async_update_data(self) -> BackupCoordinatorData:
"""Update backup manager data."""
return BackupCoordinatorData(
self.backup_manager.state,
self.backup_manager.config.data.last_attempted_automatic_backup,
self.backup_manager.config.data.last_completed_automatic_backup,
self.backup_manager.config.data.schedule.next_automatic_backup,
)
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/backup/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class BackupSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.last_successful_automatic_backup,
),
BackupSensorEntityDescription(
key="last_attempted_automatic_backup",
translation_key="last_attempted_automatic_backup",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.last_attempted_automatic_backup,
),
)


Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/backup/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
"next_scheduled_automatic_backup": {
"name": "Next scheduled automatic backup"
},
"last_attempted_automatic_backup": {
"name": "Last attempted automatic backup"
},
"last_successful_automatic_backup": {
"name": "Last successful automatic backup"
}
Expand Down
10 changes: 5 additions & 5 deletions homeassistant/components/fronius/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,16 @@
"ac_module_temperature_sensor_faulty_l3": "AC module temperature sensor faulty (L3)",
"dc_module_temperature_sensor_faulty": "DC module temperature sensor faulty",
"internal_processor_status": "Warning about the internal processor status. See status code for more information",
"eeprom_reinitialised": "EEPROM has been re-initialised",
"initialisation_error_usb_flash_drive_not_supported": "Initialisation error – USB flash drive is not supported",
"initialisation_error_usb_stick_over_current": "Initialisation error – Overcurrent on USB stick",
"eeprom_reinitialised": "EEPROM has been re-initialized",
"initialisation_error_usb_flash_drive_not_supported": "Initialization error – USB flash drive is not supported",
"initialisation_error_usb_stick_over_current": "Initialization error – Overcurrent on USB stick",
"no_usb_flash_drive_connected": "No USB flash drive connected",
"update_file_not_recognised_or_missing": "Update file not recognised or not present",
"update_file_not_recognised_or_missing": "Update file not recognized or not present",
"update_file_does_not_match_device": "Update file does not match the device, update file too old",
"write_or_read_error_occurred": "Write or read error occurred",
"file_could_not_be_opened": "File could not be opened",
"log_file_cannot_be_saved": "Log file cannot be saved (e.g. USB flash drive is write protected or full)",
"initialisation_error_file_system_error_on_usb": "Initialisation error in file system on USB flash drive",
"initialisation_error_file_system_error_on_usb": "Initialization error in file system on USB flash drive",
"error_during_logging_data_recording": "Error during recording of logging data",
"error_during_update_process": "Error occurred during update process",
"update_file_corrupt": "Update file corrupt",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/google/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/google",
"iot_class": "cloud_polling",
"loggers": ["googleapiclient"],
"requirements": ["gcal-sync==7.0.0", "oauth2client==4.1.3", "ical==9.1.0"]
"requirements": ["gcal-sync==7.0.0", "oauth2client==4.1.3", "ical==9.2.0"]
}
32 changes: 1 addition & 31 deletions homeassistant/components/huawei_lte/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from requests.exceptions import Timeout
import voluptuous as vol

from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_HW_VERSION,
Expand Down Expand Up @@ -90,36 +89,7 @@

SCAN_INTERVAL = timedelta(seconds=30)

NOTIFY_SCHEMA = vol.Any(
None,
vol.Schema(
{
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_RECIPIENT): vol.Any(
None, vol.All(cv.ensure_list, [cv.string])
),
}
),
)

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list,
[
vol.Schema(
{
vol.Required(CONF_URL): cv.url,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(NOTIFY_DOMAIN): NOTIFY_SCHEMA,
}
)
],
)
},
extra=vol.ALLOW_EXTRA,
)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)

SERVICE_SCHEMA = vol.Schema({vol.Optional(CONF_URL): cv.url})

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/local_calendar/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
"iot_class": "local_polling",
"loggers": ["ical"],
"requirements": ["ical==9.1.0"]
"requirements": ["ical==9.2.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/local_todo/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/local_todo",
"iot_class": "local_polling",
"requirements": ["ical==9.1.0"]
"requirements": ["ical==9.2.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/remote_calendar/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["ical"],
"quality_scale": "silver",
"requirements": ["ical==9.1.0"]
"requirements": ["ical==9.2.0"]
}
2 changes: 2 additions & 0 deletions homeassistant/components/teslemetry/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import Any

from tesla_fleet_api.const import Scope
from tesla_fleet_api.teslemetry import Vehicle

from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -76,6 +77,7 @@ async def async_setup_entry(
class TeslemetryButtonEntity(TeslemetryVehiclePollingEntity, ButtonEntity):
"""Base class for Teslemetry buttons."""

api: Vehicle
entity_description: TeslemetryButtonEntityDescription

def __init__(
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/teslemetry/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ class TeslemetryClimateEntity(TeslemetryRootEntity, ClimateEntity):
"""Vehicle Climate Control."""

api: Vehicle

_attr_precision = PRECISION_HALVES
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_hvac_modes = [HVACMode.HEAT_COOL, HVACMode.OFF]
Expand Down Expand Up @@ -372,7 +371,6 @@ class TeslemetryCabinOverheatProtectionEntity(TeslemetryRootEntity, ClimateEntit
"""Vehicle Cabin Overheat Protection."""

api: Vehicle

_attr_precision = PRECISION_WHOLE
_attr_target_temperature_step = 5
_attr_min_temp = 30
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/teslemetry/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any

from tesla_fleet_api.const import Scope, SunRoofCommand, Trunk, WindowCommand
from tesla_fleet_api.teslemetry import Vehicle
from teslemetry_stream import Signal
from teslemetry_stream.const import WindowState

Expand Down Expand Up @@ -103,6 +104,7 @@ async def async_added_to_hass(self) -> None:
class TeslemetryWindowEntity(TeslemetryRootEntity, CoverEntity):
"""Base class for window cover entities."""

api: Vehicle
_attr_device_class = CoverDeviceClass.WINDOW
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE

Expand Down Expand Up @@ -224,6 +226,7 @@ class TeslemetryChargePortEntity(
):
"""Base class for for charge port cover entities."""

api: Vehicle
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE

Expand Down Expand Up @@ -304,6 +307,7 @@ def _async_value_from_stream(self, value: bool | None) -> None:
class TeslemetryFrontTrunkEntity(TeslemetryRootEntity, CoverEntity):
"""Base class for the front trunk cover entities."""

api: Vehicle
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN

Expand Down Expand Up @@ -365,6 +369,7 @@ def _async_value_from_stream(self, value: bool | None) -> None:
class TeslemetryRearTrunkEntity(TeslemetryRootEntity, CoverEntity):
"""Cover entity for the rear trunk."""

api: Vehicle
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE

Expand Down Expand Up @@ -433,6 +438,7 @@ def _async_value_from_stream(self, value: bool | None) -> None:
class TeslemetrySunroofEntity(TeslemetryVehiclePollingEntity, CoverEntity):
"""Cover entity for the sunroof."""

api: Vehicle
_attr_device_class = CoverDeviceClass.WINDOW
_attr_supported_features = (
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/teslemetry/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class TeslemetryRootEntity(Entity):

_attr_has_entity_name = True
scoped: bool
api: Vehicle | EnergySite

def raise_for_scope(self, scope: Scope):
"""Raise an error if a scope is not available."""
Expand Down Expand Up @@ -248,6 +247,8 @@ def exists(self) -> bool:
class TeslemetryVehicleStreamEntity(TeslemetryRootEntity):
"""Parent class for Teslemetry Vehicle Stream entities."""

api: Vehicle

def __init__(self, data: TeslemetryVehicleData, key: str) -> None:
"""Initialize common aspects of a Teslemetry entity."""
self.vehicle = data
Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/teslemetry/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any

from tesla_fleet_api.const import Scope
from tesla_fleet_api.teslemetry import Vehicle

from homeassistant.components.lock import LockEntity
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -64,6 +65,8 @@ async def async_setup_entry(
class TeslemetryVehicleLockEntity(TeslemetryRootEntity, LockEntity):
"""Base vehicle lock entity for Teslemetry."""

api: Vehicle

async def async_lock(self, **kwargs: Any) -> None:
"""Lock the doors."""
self.raise_for_scope(Scope.VEHICLE_CMDS)
Expand Down Expand Up @@ -135,6 +138,8 @@ def _callback(self, value: bool | None) -> None:
class TeslemetryCableLockEntity(TeslemetryRootEntity, LockEntity):
"""Base cable Lock entity for Teslemetry."""

api: Vehicle

async def async_lock(self, **kwargs: Any) -> None:
"""Charge cable Lock cannot be manually locked."""
raise ServiceValidationError(
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/teslemetry/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class TeslemetryMediaEntity(TeslemetryRootEntity, MediaPlayerEntity):
"""Base vehicle media player class."""

api: Vehicle

_attr_device_class = MediaPlayerDeviceClass.SPEAKER
_attr_volume_step = VOLUME_STEP

Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/teslemetry/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ async def async_setup_entry(
class TeslemetryVehicleNumberEntity(TeslemetryRootEntity, NumberEntity):
"""Vehicle number entity base class."""

api: Vehicle
entity_description: TeslemetryNumberVehicleEntityDescription

async def async_set_native_value(self, value: float) -> None:
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/teslemetry/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ async def async_setup_entry(
class TeslemetrySelectEntity(TeslemetryRootEntity, SelectEntity):
"""Parent vehicle select entity class."""

api: Vehicle
entity_description: TeslemetrySelectEntityDescription
_climate: bool = False

Expand Down
17 changes: 14 additions & 3 deletions homeassistant/components/teslemetry/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing import Any

from tesla_fleet_api.const import AutoSeat, Scope
from tesla_fleet_api.teslemetry.vehicles import TeslemetryVehicle
from tesla_fleet_api.teslemetry import Vehicle
from teslemetry_stream import TeslemetryStreamVehicle

from homeassistant.components.switch import (
Expand Down Expand Up @@ -38,8 +38,8 @@
class TeslemetrySwitchEntityDescription(SwitchEntityDescription):
"""Describes Teslemetry Switch entity."""

on_func: Callable[[TeslemetryVehicle], Awaitable[dict[str, Any]]]
off_func: Callable[[TeslemetryVehicle], Awaitable[dict[str, Any]]]
on_func: Callable[[Vehicle], Awaitable[dict[str, Any]]]
off_func: Callable[[Vehicle], Awaitable[dict[str, Any]]]
scopes: list[Scope]
value_func: Callable[[StateType], bool] = bool
streaming_listener: Callable[
Expand All @@ -60,6 +60,16 @@ class TeslemetrySwitchEntityDescription(SwitchEntityDescription):
off_func=lambda api: api.set_sentry_mode(on=False),
scopes=[Scope.VEHICLE_CMDS],
),
TeslemetrySwitchEntityDescription(
key="vehicle_state_valet_mode",
streaming_listener=lambda vehicle, value: vehicle.listen_ValetModeEnabled(
value
),
streaming_firmware="2024.44.25",
on_func=lambda api: api.set_valet_mode(on=True, password=""),
off_func=lambda api: api.set_valet_mode(on=False, password=""),
scopes=[Scope.VEHICLE_CMDS],
),
TeslemetrySwitchEntityDescription(
key="climate_state_auto_seat_climate_left",
streaming_listener=lambda vehicle, callback: vehicle.listen_AutoSeatClimateLeft(
Expand Down Expand Up @@ -166,6 +176,7 @@ async def async_setup_entry(
class TeslemetryVehicleSwitchEntity(TeslemetryRootEntity, SwitchEntity):
"""Base class for all Teslemetry switch entities."""

api: Vehicle
_attr_device_class = SwitchDeviceClass.SWITCH
entity_description: TeslemetrySwitchEntityDescription

Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt

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

2 changes: 1 addition & 1 deletion requirements_test_all.txt

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

48 changes: 48 additions & 0 deletions tests/components/backup/snapshots/test_sensors.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,54 @@
'state': 'idle',
})
# ---
# name: test_sensors[sensor.backup_last_attempted_automatic_backup-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.backup_last_attempted_automatic_backup',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last attempted automatic backup',
'platform': 'backup',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_attempted_automatic_backup',
'unique_id': 'last_attempted_automatic_backup',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[sensor.backup_last_attempted_automatic_backup-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'Backup Last attempted automatic backup',
}),
'context': <ANY>,
'entity_id': 'sensor.backup_last_attempted_automatic_backup',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensors[sensor.backup_last_successful_automatic_backup-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
Expand Down
Loading