-
-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Added select sensor for intelligent target time to make it easi…
…er to pick a valid time. The existing time sensor is deprecated and will be removed in a future release (45 minutes dev time)
- Loading branch information
1 parent
52bb498
commit 7554228
Showing
6 changed files
with
191 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
custom_components/octopus_energy/intelligent/target_time_select.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import logging | ||
from datetime import datetime, time, timedelta | ||
import time as time_time | ||
|
||
from homeassistant.const import ( | ||
STATE_UNAVAILABLE, | ||
STATE_UNKNOWN, | ||
) | ||
from homeassistant.core import HomeAssistant, callback | ||
from homeassistant.helpers.entity import generate_entity_id | ||
|
||
from homeassistant.helpers.update_coordinator import ( | ||
CoordinatorEntity | ||
) | ||
from homeassistant.components.select import SelectEntity | ||
from homeassistant.util.dt import (utcnow) | ||
from homeassistant.helpers.restore_state import RestoreEntity | ||
|
||
from .base import OctopusEnergyIntelligentSensor | ||
from ..api_client import OctopusEnergyApiClient | ||
from ..coordinators.intelligent_settings import IntelligentCoordinatorResult | ||
from ..utils.attributes import dict_to_typed_dict | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
class OctopusEnergyIntelligentTargetTimeSelect(CoordinatorEntity, SelectEntity, OctopusEnergyIntelligentSensor, RestoreEntity): | ||
"""Sensor for setting the target time to charge the car to the desired percentage.""" | ||
|
||
def __init__(self, hass: HomeAssistant, coordinator, client: OctopusEnergyApiClient, device, account_id: str): | ||
"""Init sensor.""" | ||
# Pass coordinator to base class | ||
CoordinatorEntity.__init__(self, coordinator) | ||
OctopusEnergyIntelligentSensor.__init__(self, device) | ||
|
||
self._state = None | ||
self._last_updated = None | ||
self._client = client | ||
self._account_id = account_id | ||
self._attributes = {} | ||
self.entity_id = generate_entity_id("select.{}", self.unique_id, hass=hass) | ||
|
||
self._options = [] | ||
current_time = datetime(2025, 1, 1, 4, 0) | ||
final_time = datetime(2025, 1, 1, 11, 30) | ||
while current_time < final_time: | ||
self._options.append(f"{current_time.hour:02}:{current_time.minute:02}") | ||
current_time = current_time + timedelta(minutes=30) | ||
|
||
@property | ||
def unique_id(self): | ||
"""The id of the sensor.""" | ||
return f"octopus_energy_{self._account_id}_intelligent_target_time" | ||
|
||
@property | ||
def name(self): | ||
"""Name of the sensor.""" | ||
return f"Intelligent Target Time ({self._account_id})" | ||
|
||
@property | ||
def icon(self): | ||
"""Icon of the sensor.""" | ||
return "mdi:battery-clock" | ||
|
||
@property | ||
def extra_state_attributes(self): | ||
"""Attributes of the sensor.""" | ||
return self._attributes | ||
|
||
@property | ||
def options(self) -> list[str]: | ||
"""Return the available tariffs.""" | ||
return self._options | ||
|
||
@property | ||
def current_option(self) -> str: | ||
return self._state | ||
|
||
@callback | ||
def _handle_coordinator_update(self) -> None: | ||
"""The time that the car should be ready by.""" | ||
settings_result: IntelligentCoordinatorResult = self.coordinator.data if self.coordinator is not None and self.coordinator.data is not None else None | ||
if settings_result is None or (self._last_updated is not None and self._last_updated > settings_result.last_retrieved): | ||
return | ||
|
||
if settings_result.settings is not None: | ||
self._state = f"{settings_result.settings.ready_time_weekday.hour:02}:{settings_result.settings.ready_time_weekday.minute:02}" | ||
|
||
self._attributes = dict_to_typed_dict(self._attributes) | ||
super()._handle_coordinator_update() | ||
|
||
async def async_select_option(self, option: str) -> None: | ||
"""Change the selected option.""" | ||
parts = option.split(":") | ||
value = time(int(parts[0]), int(parts[1])) | ||
await self._client.async_update_intelligent_car_target_time( | ||
self._account_id, | ||
self._device.id, | ||
value, | ||
) | ||
self._state = value | ||
self._last_updated = utcnow() | ||
self.async_write_ha_state() | ||
|
||
async def async_added_to_hass(self): | ||
"""Call when entity about to be added to hass.""" | ||
# If not None, we got an initial value. | ||
await super().async_added_to_hass() | ||
state = await self.async_get_last_state() | ||
|
||
if state is not None: | ||
self._state = None if state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN) else state.state | ||
self._attributes = dict_to_typed_dict(state.attributes) | ||
|
||
if (self._state is None): | ||
self._state = None | ||
|
||
_LOGGER.debug(f'Restored OctopusEnergyIntelligentTargetTime state: {self._state}') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import logging | ||
|
||
from .intelligent.target_time_select import OctopusEnergyIntelligentTargetTimeSelect | ||
from .api_client import OctopusEnergyApiClient | ||
from .intelligent import get_intelligent_features | ||
from .api_client.intelligent_device import IntelligentDevice | ||
|
||
from .const import ( | ||
CONFIG_ACCOUNT_ID, | ||
DATA_CLIENT, | ||
DATA_INTELLIGENT_DEVICE, | ||
DOMAIN, | ||
|
||
CONFIG_MAIN_API_KEY, | ||
|
||
DATA_INTELLIGENT_SETTINGS_COORDINATOR | ||
) | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
async def async_setup_entry(hass, entry, async_add_entities): | ||
"""Setup sensors based on our entry""" | ||
|
||
config = dict(entry.data) | ||
|
||
if entry.options: | ||
config.update(entry.options) | ||
|
||
if CONFIG_MAIN_API_KEY in config: | ||
await async_setup_intelligent_sensors(hass, config, async_add_entities) | ||
|
||
return True | ||
|
||
async def async_setup_intelligent_sensors(hass, config, async_add_entities): | ||
_LOGGER.debug('Setting up intelligent sensors') | ||
|
||
entities = [] | ||
|
||
account_id = config[CONFIG_ACCOUNT_ID] | ||
|
||
client = hass.data[DOMAIN][account_id][DATA_CLIENT] | ||
intelligent_device: IntelligentDevice = hass.data[DOMAIN][account_id][DATA_INTELLIGENT_DEVICE] if DATA_INTELLIGENT_DEVICE in hass.data[DOMAIN][account_id] else None | ||
if intelligent_device is not None: | ||
intelligent_features = get_intelligent_features(intelligent_device.provider) | ||
settings_coordinator = hass.data[DOMAIN][account_id][DATA_INTELLIGENT_SETTINGS_COORDINATOR] | ||
client: OctopusEnergyApiClient = hass.data[DOMAIN][account_id][DATA_CLIENT] | ||
|
||
if intelligent_features.ready_time_supported: | ||
entities.append(OctopusEnergyIntelligentTargetTimeSelect(hass, settings_coordinator, client, intelligent_device, account_id)) | ||
|
||
async_add_entities(entities) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters