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
13 changes: 11 additions & 2 deletions homeassistant/components/fressnapf_tracker/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from typing import TYPE_CHECKING, Any

from fressnapftracker import FressnapfTrackerError

from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ColorMode,
Expand All @@ -16,6 +18,7 @@
from . import FressnapfTrackerConfigEntry
from .const import DOMAIN
from .entity import FressnapfTrackerEntity
from .services import handle_fressnapf_tracker_exception

PARALLEL_UPDATES = 1

Expand Down Expand Up @@ -61,12 +64,18 @@ async def async_turn_on(self, **kwargs: Any) -> None:
self.raise_if_not_activatable()
brightness = kwargs.get(ATTR_BRIGHTNESS, 255)
brightness = int((brightness / 255) * 100)
await self.coordinator.client.set_led_brightness(brightness)
try:
await self.coordinator.client.set_led_brightness(brightness)
except FressnapfTrackerError as e:
handle_fressnapf_tracker_exception(e)
await self.coordinator.async_request_refresh()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
await self.coordinator.client.set_led_brightness(0)
try:
await self.coordinator.client.set_led_brightness(0)
except FressnapfTrackerError as e:
handle_fressnapf_tracker_exception(e)
await self.coordinator.async_request_refresh()

def raise_if_not_activatable(self) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ rules:
unique-config-entry: done

# Silver
action-exceptions: todo
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
Expand Down
21 changes: 21 additions & 0 deletions homeassistant/components/fressnapf_tracker/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Services and service helpers for fressnapf_tracker."""

from fressnapftracker import FressnapfTrackerError, FressnapfTrackerInvalidTokenError

from homeassistant.exceptions import ConfigEntryAuthFailed, HomeAssistantError

from .const import DOMAIN


def handle_fressnapf_tracker_exception(exception: FressnapfTrackerError):
"""Handle the different FressnapfTracker errors."""
if isinstance(exception, FressnapfTrackerInvalidTokenError):
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="invalid_auth",
) from exception
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="api_error",
translation_placeholders={"error_message": str(exception)},
) from exception
3 changes: 3 additions & 0 deletions homeassistant/components/fressnapf_tracker/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
}
},
"exceptions": {
"api_error": {
"message": "An error occurred while communicating with the Fressnapf Tracker API: {error_message}"
},
"charging": {
"message": "The flashlight cannot be activated while charging."
},
Expand Down
13 changes: 11 additions & 2 deletions homeassistant/components/fressnapf_tracker/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from typing import TYPE_CHECKING, Any

from fressnapftracker import FressnapfTrackerError

from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
Expand All @@ -13,6 +15,7 @@

from . import FressnapfTrackerConfigEntry
from .entity import FressnapfTrackerEntity
from .services import handle_fressnapf_tracker_exception

PARALLEL_UPDATES = 1

Expand Down Expand Up @@ -43,12 +46,18 @@ class FressnapfTrackerSwitch(FressnapfTrackerEntity, SwitchEntity):

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
await self.coordinator.client.set_energy_saving(True)
try:
await self.coordinator.client.set_energy_saving(True)
except FressnapfTrackerError as e:
handle_fressnapf_tracker_exception(e)
await self.coordinator.async_request_refresh()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
await self.coordinator.client.set_energy_saving(False)
try:
await self.coordinator.client.set_energy_saving(False)
except FressnapfTrackerError as e:
handle_fressnapf_tracker_exception(e)
await self.coordinator.async_request_refresh()

@property
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/nextdns/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["nextdns"],
"quality_scale": "platinum",
"requirements": ["nextdns==4.1.0"]
"requirements": ["nextdns==5.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/portainer/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["pyportainer==1.0.21"]
"requirements": ["pyportainer==1.0.22"]
}
15 changes: 7 additions & 8 deletions homeassistant/components/shelly/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ def __init__(
self._attr_device_info = get_entity_block_device_info(coordinator, sensor_block)
self._attr_name = None # Main device entity

self._channel = cast(int, self._unique_id.split("_")[1])
self._channel = int(self._unique_id.split("_")[1])

@property
def extra_restore_state_data(self) -> ShellyClimateExtraStoredData:
Expand Down Expand Up @@ -543,8 +543,9 @@ async def set_state_full_path(self, **kwargs: Any) -> Any:
"""Set block state (HTTP request)."""
LOGGER.debug("Setting state for entity %s, state: %s", self.name, kwargs)
try:
return await self.coordinator.device.http_request(
"get", f"thermostat/{self._channel}", kwargs
return await self.coordinator.device.set_thermostat_state(
self._channel,
**kwargs,
)
except DeviceConnectionError as err:
self.coordinator.last_update_success = False
Expand Down Expand Up @@ -577,15 +578,15 @@ async def async_set_temperature(self, **kwargs: Any) -> None:
UnitOfTemperature.FAHRENHEIT,
)

await self.set_state_full_path(target_t_enabled=1, target_t=f"{target_temp}")
await self.set_state_full_path(target_t_enabled=1, target_t=target_temp)

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
if hvac_mode == HVACMode.OFF:
if isinstance(self.target_temperature, float):
self._last_target_temp = self.target_temperature
await self.set_state_full_path(
target_t_enabled=1, target_t=f"{self._attr_min_temp}"
target_t_enabled=1, target_t=self._attr_min_temp
)
if hvac_mode == HVACMode.HEAT:
await self.set_state_full_path(
Expand All @@ -599,9 +600,7 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:
if preset_index == 0:
await self.set_state_full_path(schedule=0)
else:
await self.set_state_full_path(
schedule=1, schedule_profile=f"{preset_index}"
)
await self.set_state_full_path(schedule=1, schedule_profile=preset_index)

async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
Expand Down
25 changes: 23 additions & 2 deletions homeassistant/components/teslemetry/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,9 @@ async def async_select_option(self, option: str) -> None:
self.async_write_ha_state()


class TeslemetryExportRuleSelectEntity(TeslemetryEnergyInfoEntity, SelectEntity):
class TeslemetryExportRuleSelectEntity(
TeslemetryEnergyInfoEntity, SelectEntity, RestoreEntity
):
"""Select entity for export rules select entities."""

_attr_options: list[str] = [
Expand All @@ -348,9 +350,28 @@ def __init__(
self.scoped = Scope.ENERGY_CMDS in scopes
super().__init__(data, "components_customer_preferred_export_rule")

async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
await super().async_added_to_hass()

# Restore state if it's not known
if self._attr_current_option is None:
if (state := await self.async_get_last_state()) is not None:
if state.state in self._attr_options:
self._attr_current_option = state.state

def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""
self._attr_current_option = self.get(self.key, EnergyExportMode.NEVER.value)
if value := self._value:
# Customer selected export option
self._attr_current_option = value
elif self.get("components_non_export_configured") is True:
# In VPP, Export is disabled
self._attr_current_option = EnergyExportMode.NEVER
elif self._attr_current_option == EnergyExportMode.NEVER:
# In VPP, Export is enabled, but our state shows it is disabled
self._attr_current_option = None # Unknown
# In VPP Mode, Export isn't disabled, so use last known state

async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/components/tplink_omada/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ async def async_step_reauth_confirm(
info = await self._test_login(self._omada_opts, errors)

if info is not None:
# Check the controller ID is the same as before
await self.async_set_unique_id(info.controller_id)
self._abort_if_unique_id_mismatch(reason="device_mismatch")

# Auth successful - update the config entry with the new credentials
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data=self._omada_opts
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/tplink_omada/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ rules:
comment: Service data APIs are polled every 5 minutes
brands: done
common-modules: done
config-flow-test-coverage:
status: todo
comment: "test_form_single_site is patching config flow internals, and should only patch external APIs. Must address feedback from #156697."
config-flow-test-coverage: done
config-flow: done
dependency-transparency:
status: done
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/tplink_omada/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"device_mismatch": "Please ensure you reauthenticate the same controller.",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
},
"error": {
Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/velbus/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ async def _on_update(self) -> None:
"""Handle status updates from the channel."""
self.async_write_ha_state()

@property
def available(self) -> bool:
"""Return if entity is available."""
return self._channel.is_connected()


def api_call[_T: VelbusEntity, **_P](
func: Callable[Concatenate[_T, _P], Awaitable[None]],
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/velbus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"velbus-packet",
"velbus-protocol"
],
"quality_scale": "bronze",
"quality_scale": "silver",
"requirements": ["velbus-aio==2026.1.1"],
"usb": [
{
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/velbus/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ rules:
test-before-configure: done
test-before-setup: done
unique-config-entry: done

# Silver
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: todo
entity-unavailable: done
integration-owner: done
log-when-unavailable: done
parallel-updates: done
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/velux/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["pyvlx"],
"requirements": ["pyvlx==0.2.26"]
"requirements": ["pyvlx==0.2.27"]
}
6 changes: 3 additions & 3 deletions requirements_all.txt

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

6 changes: 3 additions & 3 deletions requirements_test_all.txt

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

Loading
Loading